Any good new ways in C ++ 11 to store, as members, "cloned" objects of other "hierarchical classes"?

We have the Base and Derived class, which comes from Base .

In some other class, we want to have a member of type shared_ptr<Base> .

We cannot use the Base type directly, because direct copying will exclude subclasses.

However, we still want to “copy” the Base object (or subclass) on top of the construct, because we want to exclude the possibility of its modification.

The classic way to handle this is to put the virtual member function clone() in the Base class, which every subclass of Base can implement. Each clone() then simply returns a "copy" of itself - for example, Derived will return make_shared<Derived>(*this) .

The problem with this approach is that each new subclass of Base is required to implement this clone() function. The code in each clone() is rather a template, and it seems somewhat unnatural to repeat it all the time.

Any better ways to do this with C ++ 11?

+4
source share
1 answer

This could always be done in plain C ++:

 struct base { virtual ~base () {} virtual base* clone () = 0; virtual void foo () = 0; }; template <typename T> struct base_impl : base { T* clone () { return new T (*static_cast<T*> (this)); } }; struct derived : base_impl<derived> { void foo () { ... } }; struct derived2 : base_impl<derived2> { void foo () { ...} }; 

and etc.

You can improve this with C ++ 11: you can use unique_ptr<base> (but you lose the return type of covariance), you can make the base_impl private destructor and use friend T

I agree that in this case it is not very flexible, but:

  • many multi-level hierarchies are not very common
  • The cloning features are not very useful.
  • the design is still extensible and goes beyond cloning: the use of templates as a way to automate template code is mainly used, for example. ATL and WTL. Find the "curiously repeating pattern template."

Another solution. This can probably be improved in various ways, but I think you cannot avoid the two functions of the clone:

 struct base { std::unique_ptr<base> clone () { return std::unique_ptr<base> (do_clone ()); } private: virtual base *do_clone () = 0; }; template <typename T> struct base_impl : base { std::unique_ptr<T> clone () { return std::unique_ptr<T> (static_cast<T*> (do_clone ())); } private: base *do_clone () { return new T (*static_cast<T*> (this)); } }; 
+5
source

All Articles