c++ - 带有智能指针的继承对象的深拷贝
问题描述
我不确定使用包含继承对象的智能指针制作对象的深层副本的最佳/最干净的解决方案是什么。归结为以下代码
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
什么?我可以想到两种方法,都有一些缺点:
- 在基类中创建一个虚
A* clone()
方法并在每个继承的类中重载它(如此处所述)。缺点: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;
};
上面使用的是原始指针,并且可能会通过返回 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
你可以在这里看到它。
推荐阅读
- java - Java & gradle -> 仅包含库中的特定包
- ruby - 使用 Ruby 服务器作为 API 中间人
- python-3.x - 熊猫向前向后填充列级别内的列
- ios - iOS - 在后台推送通知上刷新数据(发出 Api 请求)
- powerquery - Power Query 将列表中的记录转换为列
- javascript - d3js 版本 3 到 4 用于切换条形图
- asynchronous - UWP:抛出/引发不会导致应用程序崩溃,异常被忽略
- javascript - 警告:函数作为反应子问题无效......是因为我的容器吗?
- vim - 当我退出插入模式时,如何防止 Vim 复制我的文本?
- excel - 如何将多行合并为一行