与CRTP clonable类无关的协变类型

时间:2015-05-15 05:22:28

标签: 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 *')

班级' 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> {

};

3 个答案:

答案 0 :(得分:3)

即使B确实来自Clonable<B>,这里的问题是Clonable<B>构造无效,因为它定义了

B* clone() const override

当然不是AbstractClonable::clone()的覆盖,因为此时编译器不会将B视为AbstractClonable的子级。所以我认为问题在于编译器无法构建Clonable<B>的{​​{1}}基础。

解决方法(但与您想要的并不完全相同)是定义

B
Clonable* clone() const override 中的

。正如您在评论中提到的,您还可以定义一个自由函数

Clonable

相关:Derived curiously recurring templates and covariance

答案 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 *。