【问题标题】:copy constructor on base class基类上的复制构造函数
【发布时间】:2018-10-29 09:10:51
【问题描述】:

cpp 核心指南中的列表 C.67 说:基类应该禁止复制,如果需要“复制”,则提供虚拟克隆。

如果复制构造函数在基类中定义为已删除,则基类和所有派生类的移动操作也将被禁止。

另一方面,移动操作可能会提高性能。我的问题是,当我们设计一个类层次结构时,我们应该采用什么样的现实方法?

假设我们有以下类层次结构?我们应该如何设计 A 和 B 以正确支持复制和移动操作。

class A{
public:
  A(const std::string& as) = deleted;
  //should we define other copy/move operators?

  virtual void foo();//
  virtual ~A();//

private:
  std::string s;
};

class B: public A{
public:
  //how do we define copy/move operators?

  void foo() override;
  ~B() override;
private:
  std::vector<std::string> vs;
};

【问题讨论】:

  • 这与您在使用复制构造函数时遇到的问题相同。如果你只有一个Base *,你怎么知道要移动哪个派生类?如果你有好的情况,可以将构造函数重新添加到派生类中。
  • 什么“类层次结构”?

标签: c++ copy move


【解决方案1】:

困惑

复制vs.克隆

首先,请注意clone 不是“多态类型对象的副本”:它们只是具有不同语义的不同操作。

  • 复制(通过复制构造函数)的意思是“用另一个的创建一个静态指定类型的对象”。 (回想一下,构造函数不能是virtual,因为需要一个类可以提供行为的当前对象。)用户必须指定类型,并且应该期望复制的对象被“重新解释”(切片)为 已知,如果它实际上是派生类型,则指定类型。
  • clone动态已知 派生类的对象复制为 类的另一个对象。由于参数决定了结果的类型,用户不能指定它,并且确实(静态地)不知道选择了什么。 (堆分配是必然的结果。)

您想要哪个取决于您希望结果具有什么样的生命周期和类型(包括“与那个相同的类型”作为选择)。我觉得令人费解的是,有人会编写一个副本(例如,一个按值参数,其指定 类型是一个具体的基类)并且对他们选择的内容感到惊讶。

虚拟分配

接下来,请注意,抽象类无需担心切片,除非在赋值时(必须通过引用)。赋值可以是virtual(因为一个对象已经存在),但它不能静态避免切片,因为类型不需要匹配:

struct B {
  virtual ~B()=default;
  virtual B& operator=(const B&)=default;
  // ...
};
struct D1 : B {
  D& operator=(const B&) override;
  // ...
};
struct D2 : B {/* ... */};

void f() {
  B &&b=D1();
  b=D2();  // ok
}

作业必须只使用常见的B 部分,或者……抛出?如果分配可能失败,将其作为函数提供会更清楚:如果类型不同,可能会返回 falsebool assign_like(const B&amp;) &amp;;

保护

因此,如果我们想避免切片的风险,我们确实必须至少对分配做一些事情。 Core Guidelines 删除赋值运算符的想法是合理的,但我只会在每个抽象基类中使用protected

仅限混凝土叶片

如果您从不从具体类继承,那么您只需要防止切片:叶类中的隐式 (public) 特殊成员函数不切片,自动使用基类的对应SMF,并且可以根据需要自动使用。 (例如,具体类可以通过值传递。)

“深”层次结构

在具体的基类中,每个 SMF 都有两种选择:

  1. 无论如何都要设为protected否认故意复制对象的可能性(即使源的完整对象类型是静态已知的)。
  2. 让它可用,并将任何对类层次结构感到困惑的用户发送到此处,以了解复制和 clone 之间的区别(以及“完全 virtual”分配的不可能性)。

【讨论】:

    猜你喜欢
    • 2013-06-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-24
    • 2012-02-28
    • 1970-01-01
    • 1970-01-01
    • 2012-01-02
    相关资源
    最近更新 更多