首页 > 解决方案 > 带有智能指针的继承对象的深拷贝

问题描述

我不确定使用包含继承对象的智能指针制作对象的深层副本的最佳/最干净的解决方案是什么。归结为以下代码

class A {};

class D1 : public A{
public:
    int x1 = 0;
};

class D2 : public A {
public:
    int x2 = 2;
};


class V {
public:
    V(A* a) : ptr(a) {}
    std::unique_ptr<A> ptr;
};    

void run() {
    std::vector<V> v;
    v.push_back(V(new D1));
    v.push_back(V(new D2));
    /// I want to make a deep copy of v here
}

其中向量v包含两个类型的对象,D1以及D2制作深度副本的最短/最优雅的方法是v什么?我可以想到两种方法,都有一些缺点:

  1. 在基类中创建一个虚A* clone()方法并在每个继承的类中重载它(如此所述)。缺点:clone方法需要在每个继承类中实例化,可能有多个。
  2. 为 .创建一个复制构造函数/赋值运算符V。使用dynamic_cast<D1/D2>,检查附加了哪种继承对象并为该特定类型制作副本。缺点:需要遍历所有继承类的拷贝构造函数V

标签: c++c++11polymorphismsmart-pointersdeep-copy

解决方案


选项 1 不需要您在V每次将类添加到A. 此外,如果添加的类没有实现clone,您将得到一个漂亮的编译器错误,而不是像选项 2 中那样在运行时构建和失败的所有内容。

所以选项1更好。但你是对的,它有点重复。您必须为许多不同的类型编写类似的代码。幸运的是,C++ 有一种机制来处理这个问题:模板。

使用CRTP类,我们可以clone自动实现该功能。所有需要做的就是从中间人继承,而不是D1直接继承:D2A

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

template<class C>
struct AClone : A {
  A* clone() const override {
    return new C(*static_cast<C const*>(this));
  }
};

class D1 : public AClone<D1> {
public:
    int x1 = 0;
};

class D2 : public AClone<D2> {
public:
    int x2 = 2;
};

上面使用的是原始指针,并且可能会通过返回 aunique_ptr来改进,但为了简洁起见,这就是归结为的想法。

还可以在此clone功能中添加一些防御性编程。

static_assert(std::is_convertible<C*, A*>::value,"");
static_assert(std::is_convertible<C*, AClone*>::value,"");
// These two check `C` is derived unambiguasly from `A` via this specialization

assert(typeid(C) == typeid(*this));
// Check the most derived type is as expected, suggested by Deduplicator

你可以在这里看到它。


推荐阅读