我不确定用包含继承对象的智能指针对对象进行深层复制的最佳/最干净的解决方案是什么。给出以下代码,将其归结为
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
}
在 vector
v
包含D1
和D2
类型的两个对象的情况下,制作v
的深拷贝的最短/最优雅的方法是什么?我可以想到两种方式,都有一些缺点:A* clone()
方法,并在每个继承的类中重载它(如here所述)。缺点:clone方法需要在每个继承的类中实例化,并且可能有多个。 V
创建一个复制构造函数/赋值运算符。使用dynamic_cast<D1/D2>
,检查附加了哪种继承对象,并为该特定类型创建一个副本。缺点:需要遍历V
的副本构造函数中的所有继承的类。 最佳答案
选项1不需要每次将类添加到V
下的层次结构时都修改A
。此外,如果添加的类未实现clone
,您将得到一个漂亮的编译器错误,而不是像选项2中那样在运行时生成和失败的所有内容。
因此,选项1更好。但是您是正确的,它有些重复。您必须为许多不同的类型编写类似的代码。幸运的是,C++有一种机制可以处理:模板。
使用CRTP类,我们可以自动实现clone
函数。 D1
和D2
所需要做的就是从中间人继承,而不是直接从A
继承:
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;
};
上面使用的是原始指针,可以通过返回
unique_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
您可以实时观看here。