Curiously recurring patterns and covariance obtained

Suppose I have a base class that clones derived classes:

class Base { public: virtual Base * clone() { return new Base(); } // ... }; 

I have a set of derived classes that are implemented using a curiously repeating template pattern:

 template <class T> class CRTP : public Base { public: virtual T * clone() { return new T(); } // ... }; 

And I'm trying to extract more from the following:

 class Derived : public CRTP<Derived> { public: // ... }; 

I get compilation errors as a result of:

 error C2555: 'CRTP<T>::clone': overriding virtual function return type differs and is not covariant from 'Base::clone' 

I understand that this is probably the result of the compiler not fully knowing the Derived inheritance tree when creating CRTP. In addition, the replacement of the return type (T *) with (Base *) is also compiled. However, I would like to know if there is work around which semantics persist.

+8
source share
2 answers

Bad workaround.

 class Base { protected: virtual Base * clone_p() { return new Base(); } }; template <class T> class CRTP : public Base { protected: virtual CRTP* clone_p() { return new T; } public: T* clone() { CRTP* res = clone_p(); return static_cast<T*>(res); } }; class Derived : public CRTP<Derived> { public: }; 

Use dynamic_cast<> instead of static if you think this is more secure.

+3
source

If you can use a different syntax to specify full types, you can do the following (warning: untested code):

Start with the machine first:

 // this gives the complete type which needs to be used to create objects // and provides the implementation of clone() template<typename T> class Cloneable: public T { public: template<typename... U> Cloneable(U&&... u): T(std::forward<U>(u) ...) {} T* clone() { return new Cloneable(*this); } private: // this makes the class complete // Note: T:: to make it type dependent, so it can be found despite not yet defined typename T::CloneableBase::CloneableKey unlock() {} }; // this provides the clone function prototype and also makes sure that only // Cloneable<T> can be instantiated class CloneableBase { template<typename T> friend class Cloneable; // this type is only accessible to Clonerable instances struct CloneableKey {}; // this has to be implemented to complete the class; only Cloneable instances can do that virtual CloneableKey unlock() = 0; public: virtual CloneableBase* clone() = 0; virtual ~CloneableBase() {} }; 

OK, now the actual class hierarchy. This is pretty standard; no CRTP intermediates or other complications. However, no class implements the clone function, but all inherit the declaration (directly or indirectly) from CloneableBase .

 // Base inherits clone() from CloneableBase class Base: public CloneableBase { // ... }; // Derived can inherit normally from Base, nothing special here class Derived: public Base { // ... }; 

Here, as you then create the objects:

 // However, to create new instances, we actually need to use Cloneable<Derived> Cloneable<Derived> someObject; Derived* ptr = new Cloneable<Derived>(whatever); // Now we clone the objects Derived* clone1 = someObject.clone(); Derived* clone2 = ptr->clone(); // we can get rid og the objects the usual way: delete ptr; delete clone1; delete clone2; 

Note that a Cloneable<Derived> is-a Derived (this is a subclass), so you only need to use Cloneable for construction, and otherwise you can pretend to work with Derived objects (well, tyepinfo also identifies it as Cloneable<Derived> ).

+1
source

All Articles