派生奇怪的循环模板和协方差
假设我有一个克隆派生类的基类:
class Base
{
public:
virtual Base * clone()
{
return new Base();
}
// ...
};
我有一组派生类,它们使用奇怪的循环模板模式实现:
template <class T>
class CRTP : public Base
{
public:
virtual T * clone()
{
return new T();
}
// ...
};
我试图从这样的进一步得出:
class Derived : public CRTP<Derived>
{
public:
// ...
};
编译错误的影响是:
error C2555: 'CRTP<T>::clone': overriding virtual function return type differs and is not covariant from 'Base::clone'
我意识到这可能是编译器在实例化CRTP时不完全知道Derived的继承树的结果。 此外,用(Base *)替换返回类型(T *)也会被编译。 但是,我想知道是否存在保留上述语义的工作。
一个不太漂亮的解决方法。
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:
};
如果您觉得它更安全,请使用dynamic_cast<>
而不是static
。
如果您不得不使用不同的语法来指定完整类型,则可以执行以下操作(警告:未经测试的代码):
我们首先从机器开始:
// 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中间体或其他并发症。 但是没有类实现clone
函数,但都从CloneableBase
继承了声明(直接或间接)。
// Base inherits clone() from CloneableBase
class Base:
public CloneableBase
{
// ...
};
// Derived can inherit normally from Base, nothing special here
class Derived:
public Base
{
// ...
};
以下是您如何创建对象的方法:
// 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;
请注意, Cloneable<Derived>
是Derived
(它是一个子类),因此您只需要使用Cloneable
来构建,否则就可以假装使用Derived
对象(好吧, tyepinfo
也会将它识别为Cloneable<Derived>
)。
上一篇: Derived curiously recurring templates and covariance
下一篇: Looking for the timeout properties of native java CORBA on the client