Gui*_*cot 6 c++ multiple-inheritance crtp cloneable covariant
我正在尝试使用CRTP实现Clonable类.但是,我需要具有纯虚拟克隆方法的抽象类,由子类重写.为了实现这一点,我需要克隆函数来返回协变返回类型.我在下面制作了这段代码,编译器向我大喊这个错误:
main.cpp:12:5: error: return type of virtual function 'clone' is not covariant with the return type of the function it overrides ('B *' is not derived from 'AbstractClonable *')
Run Code Online (Sandbox Code Playgroud)
类'B'似乎是AbstractClonable的子类,甚至是双向的!我怎么解决这个问题?非常感谢你.我尝试使用clang 3.6和GCC 4.9.2
struct AbstractClonable {
virtual AbstractClonable* clone() const = 0;
};
template<typename T>
struct Clonable : virtual AbstractClonable {
T* clone() const override {
return new T{*dynamic_cast<const T*>(this)};
}
};
struct A : virtual AbstractClonable {
};
struct B : A, Clonable<B> {
};
Run Code Online (Sandbox Code Playgroud)
即使B确实是从 派生的Clonable<B>,这里的问题是Clonable<B>构造是无效的,因为它定义
B* clone() const override
Run Code Online (Sandbox Code Playgroud)
这当然不是 的覆盖AbstractClonable::clone(),因为此时编译器没有B将AbstractClonable. 所以我相信这个问题奠定了一个事实,即编译器无法建立Clonable<B>的基地B。
一种解决方法(但与您想要的并不完全相同)是定义
Clonable* clone() const override
Run Code Online (Sandbox Code Playgroud)
在Clonable。正如您在评论中提到的,您还可以定义一个自由函数
template<typename T>
T* clone(const T* object)
{
return static_cast<T*>(object->clone());
}
Run Code Online (Sandbox Code Playgroud)
是的,B是从 派生的AbstractClonable,但是编译器不知道在实例化过程中,Clonable<B>因为B在那时仍然不完整。
C++14 §10.3/8:
如果协变返回类型中的类类型
D::f与 的不同B::f,则返回类型中的类类型D::f应在声明点完整D::f或为类类型D。
类具有在协变返回类型中使用自身的特殊权限。其他类,包括 CRTP 基类,需要等到类完成后再声明协变函数。
您可以使用非虚拟接口习惯用法 (NVI) 解决该问题:
class AbstractClonable {
protected:
virtual AbstractClonable* do_clone() const = 0;
public:
AbstractClonable *clone() const {
return do_clone();
}
};
template<typename T>
class Clonable : public virtual AbstractClonable {
Clonable* do_clone() const override { // Avoid using T in this declaration.
return new T{*dynamic_cast<const T*>(this)};
}
public:
T *clone() const { // But here, it's OK.
return static_cast< T * >( do_clone() );
}
};
Run Code Online (Sandbox Code Playgroud)