7

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

derived_class.cc:15:15:错误:默认此复制构造函数将在其第一次声明后将其删除 DerivedClass::DerivedClass(const DerivedClass &) = default;

derived_class.h:9:22:注意:“DerivedClass”的复制构造函数被隐式删除,因为基类“virtual_functions::BaseClass”有一个已删除的复制构造函数类 DerivedClass:public BaseClass {

base_class.h:11:3:注意:'BaseClass' 已在此处明确标记为已删除 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;
4

3 回答 3

7

您不能阻止子类定义自己的复制/移动构造函数。也就是说,它会阻止它“开箱即用”,这意味着如果你不提供一个,或者使用内联默认构造函数,它也会被标记为已删除。当您尝试将构造函数定义为默认值时,您在此处出现错误的原因是,当成员或基础已隐式删除它时,不允许您在超出范围的定义中执行此操作。如果你用过

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

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

于 2019-03-05T16:42:37.280 回答
6

删除基类中的复制和移动构造函数/赋值运算符是否足够?

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

我看到了一个 SO 答案,它似乎暗示派生类可以显式声明复制或移动构造函数,尽管已从基类中删除

这是对的。你无法阻止这一点。好吧,您可以通过声明类 final 来防止这种情况。那么就不能有派生类,因此派生类是不可复制的。

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

于 2019-03-05T16:41:08.240 回答
3

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

但是派生类可以使用其默认 ctor 显式构造其基类:

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

等等……这个类DerivedClass现在是可复制的,尽管它的基类不是!

于 2019-03-05T16:57:43.073 回答