在 C++ 中复制具有多态成员的对象

Copying an object with a polymorphic member in C++

我想表达的是,每个类型 V 的对象都拥有一个类型 B 的对象。B 是一个多态类型,因此通过指针或引用访问以防止切片 (C.145)。我觉得很自然地表达如下

    class B {};
    
    class V {
    public:
        unique_ptr<B> p;
    };

我现在可以推导 B 并将推导的结果分配给 p,这样

    class D : public B {};
    
    V x;
    x.p = make_unique<D>();

因为B是多态类型,建议抑制复制和移动以防止切片(C.67)。

    B(const B&) = delete;
    // etc...

不可能复制 p,因为它是一个 unique_ptr,我现在也阻止了深度复制,除非实现了克隆功能 (C.130)。虚拟克隆功能的实现是否表明设计不当?这似乎是一种解决方法。

通过遵循 C++ Core Guidelines 中的这两条规则,我阻止了 V 的复制。如果 V 是图中的一个顶点,并且必须复制图,那么我就给自己制造了一个问题;无法再复制任何图形。为 V 实现自定义复制分配并不能解决该问题,因为不可能对 p 进行深度复制。

在网上找了一圈,没有找到感觉自然的解决方案,我断定我的思路一定有很大的问题。拥有多态成员是个坏主意吗?如果不应该复制多态对象,那么就不能复制任何拥有另一个多态对象的对象。

成员可以是 shared_ptr,但语义会出错,因为这不是共享对象。我缺乏一种表达明显易于概念化的东西的方法。如何在不牺牲语义的情况下复制拥有另一个多态对象的对象?每 post 我读到有人提出关于复制 unique_ptr、深度复制等的问题,通常都会得到一个需要牺牲的答案,很可能是因为解决问题的方式问题一开始就错了。我觉得有一个非常简单而优雅的解决方案。

你需要问自己一个问题:为什么 B 不能被复制?

你描述的例子,一个图拥有一个(或可能多个)顶点显示相反:B 应该是可复制的! 你不想要的是两个图共享同一个顶点实例。

因此您可以按照这些行为 V 创建复制构造函数/克隆方法:

V::V(const V& other)
{
  p = other.p->clone();
}

std::unique_ptr<B> D::clone()
{
  return std::make_unique<D>(...);
}

查看 this article 以获得更好的解释。