Derived curiously recurring templates and covariance
假设我有一个克隆派生类的基类:
1 2 3 4 5 6 7 8 9 10 | class Base { public: virtual Base * clone() { return new Base(); } // ... }; |
我有一组派生类,这些派生类是使用奇怪的循环模板模式实现的:
1 2 3 4 5 6 7 8 9 10 11 | template <class T> class CRTP : public Base { public: virtual T * clone() { return new T(); } // ... }; |
我试图从中得到进一步的结论:
1 2 3 4 5 | class Derived : public CRTP<Derived> { public: // ... }; |
我得到的编译错误影响:
1 | error C2555: 'CRTP<T>::clone': overriding virtual function return type differs and is not covariant from 'Base::clone' |
我意识到这可能是由于编译器在实例化crtp时不完全了解派生的继承树。此外,用(base*)替换返回类型(t*)也会编译。但是,我想知道是否有一个保留了上述语义的工作。
A不是很好的解决方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | 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: }; |
如果你觉得更安全的话,用
如果必须使用不同的语法来指定完整类型,则可以执行以下操作(警告:未测试代码):
我们先从机器开始:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | // 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() {} }; |
好了,现在是实际的类层次结构。这是相当标准的,没有CRTP中间体或其他并发症。但是,没有类实现
1 2 3 4 5 6 7 8 9 10 11 12 13 | // Base inherits clone() from CloneableBase class Base: public CloneableBase { // ... }; // Derived can inherit normally from Base, nothing special here class Derived: public Base { // ... }; |
下面是创建对象的方法:
1 2 3 4 5 6 7 8 9 10 11 12 | // 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; |
注意,