我尝试使用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 *')
班级' 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> {
};
答案 0 :(得分:3)
即使B
确实来自Clonable<B>
,这里的问题是Clonable<B>
构造无效,因为它定义了
B* clone() const override
当然不是AbstractClonable::clone()
的覆盖,因为此时编译器不会将B
视为AbstractClonable
的子级。所以我认为问题在于编译器无法构建Clonable<B>
的{{1}}基础。
解决方法(但与您想要的并不完全相同)是定义
B
Clonable* clone() const override
中的。正如您在评论中提到的,您还可以定义一个自由函数
Clonable
答案 1 :(得分:3)
是的,B
派生自AbstractClonable
,但编译器在实例化Clonable<B>
期间并不知道,因为此时B
仍然不完整。< / p>
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() );
}
};
答案 2 :(得分:0)
我认为问题在于
T* clone() const override{
return new T{*dynamic_cast<const T*>(this)};
}
返回B *而不是AbstractClonable *。