防止为每个子类编写克隆方法

时间:2015-02-15 08:43:29

标签: c++

以下是我的案例:

class A
{
public:
    virtual A* clone() = 0;
};

class B : public A
{
    virtual B* clone() override
    { 
        return new B();
    }
};

现在在我的代码中,A的100%子楼只实现clone方法,只与类D完全相同,我有返回类型D并创建当然是D的对象。

如何防止此重复?哪些模式或技巧可以帮助?

我曾考虑使用CRTP pattern,但它使用模板,我的功能是虚拟的。我们了解模板和虚拟功能是不兼容的。

NVI pattern也不起作用,因为克隆方法的返回类型不同。

1 个答案:

答案 0 :(得分:3)

[class.virtual] / 8:

  

如果协变返回类型D::f中的类类型不同   B::f的类型,返回类型D::f中的类类型应为   在D::f声明或完成该课程时完成   输入D

因此,CRTP不能完美地工作,因为引用派生类的模板参数将是一个不完整的类型,因此协变返回类型很难模拟。

然而,这是一个尝试:

class A
{
public:
    virtual A* clone() = 0;
};

namespace detail {
    template <typename T>
    struct Cloner : A {
        using A::A; // For constructors
        virtual A* clone() override {return new T;}
    };
}

template <typename T>
struct Cloner : detail::Cloner<T> {
    using detail::Cloner<T>::Cloner; // For constructors

    // For callers 
    template <class=void>
    T* clone() {return static_cast<T*>(detail::Cloner<T>::clone());}
};

class B : public Cloner<B>
{
};

Demo

注意两件事:

  • 返回指向派生类类型的指针的clone的重载是一个函数模板。这样我们就不会覆盖虚函数clone:如果我们愿意,代码就会格式不正确,因为返回类型不是协变的(参见上文)。

  • 因为clone是一个函数模板,为了确保它完全被调用,我们可以让它隐藏虚拟clone函数。这是通过继承实现的:派生类中的名称隐藏了基类中的名称。因此,如果我们通过B - 指针/引用调用,我们将获得相应的返回类型(B*),因为在::Cloner之前detail::Cloner会查找该名称。 / p>