C ++通过调用基类来优雅地克隆派生类

时间:2016-03-23 22:23:42

标签: c++ inheritance clone

我需要克隆一个派生类,只给出一个引用或指向基类的指针。以下代码完成了这项工作,但似乎并不优雅,因为我将样板代码放入许多派生类C,D,E中,这些派生类是B(未显示)的兄弟,只调用默认的复制构造函数每个。不是默认的复制构造函数是什么,只要它可以是虚拟的吗?

有更好的方法吗?

制作虚拟赋值运算符是错误的,因为我不希望C分配给B,B到D等,只需克隆B,C,D或E.

#include <iostream>
using namespace std;

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

class B : public A {
    int i;
    public:
    virtual A* clone() { 
        cout << "cloned B" << endl;
        return new B(*this);
    }
    virtual ~B() { cout << "destroyed b" << endl; }
};

int main() { 
    A* a = new B(); 
    A* aa = a->clone();
    delete a; 
    delete aa; 
    return 0;
}

3 个答案:

答案 0 :(得分:4)

您可以始终将所有克隆逻辑粘贴到层次结构中间的自己的类中:

template <class Derived, class Base>
class CloneCRTP : public Base {
public:
    Derived* clone() const override {
        return new Derived(static_cast<Derived const&>(*this));
    }
};

然后:

class B : public CloneCRTP<B, A>
{
    int i;
public:
    virtual ~B() { cout << "destroyed b" << endl; }        
};

不再需要样板。

答案 1 :(得分:2)

您可以依赖CRTP习语 它遵循一个最小的工作示例:

struct B {
    ~virtual ~B() { }
    virtual B* clone() = 0;
};

template<class C>
struct D: public B {
    B* clone() {
        return new C{*static_cast<C*>(this)};
    }
};

struct S: public D<S> { };

int main() {
    B *b1 = new S;
    B *b2 = b1->clone();
    delete b1;
    delete b2;
}

答案 2 :(得分:0)

要实现与协变返回类型一样工作的克隆,需要一些更复杂的CRTP:

class Shape {
    // virtual
    virtual Shape* do_clone() const = 0;
public:
    virtual ~Shape() {}
    // non-virtual
    Shape* clone() const {
        return do_clone();
    }
    // ...
};

template <class Derived, class Base>
class CloneCRTP : public Base {
    // virtual
    Shape* do_clone() const override {
        return new Derived(static_cast<Derived const&>(*this));
    }
public:
    // non-virtual
    Derived* clone() const {
        return static_cast<Derived*>(do_clone());
    }    
};

用法:

class Rectangle: public CloneCRTP<Rectangle, Shape> { /*...*/ };    
class Triangle: public CloneCRTP<Triangle, Shape> { /*...*/ };

int main() {
    Rectangle* r1 = new Rectangle{};

    // getting the proper type from clone:
    Rectangle* rcopy = r1->clone();

    delete rcopy;
    delete r1;

    Triangle t1{};

    // getting the proper type from clone:
    Triangle* tcopy = t1.clone();

    delete tcopy;
}

代码:http://coliru.stacked-crooked.com/a/d8781deee5f7f6ea