删除基 class 中的复制和移动 constructors/assignment 运算符是否足够?

Is deleting copy and move constructors/assignment operators in base class enough?

如果我有一个抽象基 class 并且我想让所有派生的 classes 不可复制和不可移动是否足以声明在基 class 中删除的这些特殊成员函数?我想确保我的整个 class 层次结构是不可复制和不可移动的,并且想知道我是否可以不必在每个派生 class 中声明这 4 个特殊成员函数已删除。我看到了一个 SO 答案,它似乎暗示派生的 class 可以显式声明一个复制或移动构造函数,尽管它已从基础 class 中删除,但是当我尝试以下示例时会导致编译错误定义一个默认的复制赋值运算符,所以我不确定。这是错误:

derived_class.cc:15:15: error: defaulting this copy constructor would delete it after its first declaration DerivedClass::DerivedClass(const DerivedClass &) = default;

derived_class.h:9:22: note: copy constructor of 'DerivedClass' is implicitly deleted because base class 'virtual_functions::BaseClass' has a deleted copy constructor class DerivedClass : public BaseClass {

base_class.h:11:3: note: 'BaseClass' has been explicitly marked deleted here BaseClass(const BaseClass &) = delete;

// base_class.h
class BaseClass {
public:
  BaseClass(const BaseClass &) = delete;
  BaseClass(BaseClass &&) = delete;
  BaseClass &operator=(const BaseClass &) = delete;
  BaseClass &operator=(BaseClass &&) = delete;
  virtual ~BaseClass() = default;
  virtual bool doSomething() = 0;

protected:
  BaseClass(std::string name);

private:
  std::string name_;
};

// derived_class.h
class DerivedClass : public BaseClass {
public:
  DerivedClass();
  DerivedClass(const DerivedClass &);
  bool doSomething() override;
};

// derived_class.cc
DerivedClass::DerivedClass(const DerivedClass &) = default;

Is deleting copy and move constructors/assignment operators in base class enough?

足以防止隐式生成复制和移动构造函数/赋值运算符。

I saw a SO answer where it seemed to imply that a derived class could explicitly declare a copy or move constructor despite being deleted from the base class

这是正确的。你无法阻止这一点。好吧,您可以通过声明 class final 来防止这种情况。则不能派生classes,因此派生classes不可复制。

当然,这种显式声明的复制构造函数(和其他)将无法复制不可复制的基础子对象。构造函数必须使用 BaseClass(std::string) 并且赋值运算符不能以任何方式修改基对象的状态(除非他们使用一些技巧来绕过访问说明符封装)。

您不能阻止子 class 定义自己的 copy/move 构造函数。也就是说,它会阻止它 "out of the box",这意味着如果你不提供一个,或者使用内联默认构造函数,它也会被标记为已删除。当您尝试仅将构造函数定义为默认构造函数时出现错误的原因是,当成员或基类已隐式删除它时,不允许您在行外定义中执行此操作。你用过吗

class DerivedClass : public BaseClass {
public:
  DerivedClass(const DerivedClass &) = default;
  bool doSomething() override;
};

然后代码会编译,如果你真的尝试调用复制构造函数,你只会得到一个错误。这是有效的,因为即使成员或基隐式删除它并且最终结果是构造函数被隐式删除,也允许内联隐式默认值。

您不能阻止派生的 class 声明 copy/move 构造函数,但它们不能被默认:默认的复制构造函数或派生的 class 会尝试调用的复制构造函数它的基础(移动相同)。

但是派生的 class 可以使用其默认构造函数显式构造其基数:

class DerivedClass : public BaseClass {
public:
  DerivedClass();
  DerivedClass(const DerivedClass &): BaseClass() {
      // copy ctor for the derived part
  }
  bool doSomething() override;
};

Et voila...class DerivedClass 现在可以复制,尽管它的基础 class 不是!