零规则与基类析构函数

rule of zero vs. base class destructors

提问人:Nico Schlömer 提问时间:1/2/2017 最后编辑:Nico Schlömer 更新时间:1/3/2017 访问量:1147

问:

我有一个基类和一个派生类,我希望编译器为我自动生成移动构造函数和移动赋值运算符。遵循零法则,我将所有内存管理留给编译器,只使用 2 级类(没有原始指针、数组等):BaseD

#include <iostream>

class Base{
  public:
    Base(): a_(42) {}
    virtual void show() { std::cout << "Base " << a_ << std::endl; }

  private:
    int a_;
};

class D : Base {
  public:
    D(): b_(666) {}
    void show() { std::cout << "D " << b_ << std::endl; }

  private:
    int b_;
};

int main() {
  Base b;
  b.show();
  D d;
  d.show();
  return 0;
}

应该就是这样,对吧?

输入 C++ 核心准则

基类析构函数应为公共和虚拟,或受保护和非虚拟。

啊,所以我想我必须添加一个析构函数。但这将取消自动生成的移动函数!Base

这里的清洁方法是什么?

C++ C++11 零法则

评论

4赞 king_nak 1/2/2017
您可以根据需要将析构函数声明为公共虚拟或受保护。= default
0赞 iammilind 1/2/2017
强相关:为什么析构函数禁用隐式移动方法的生成?

答:

8赞 AMA 1/2/2017 #1

您可以编译器生成的所有内容。 请参阅(底部):http://en.cppreference.com/w/cpp/language/rule_of_three= default

在您的案例中,它可能看起来像这样:

class Base{
  public:
    Base(): a_(42) {}
    Base(const Base&) = default;
    Base(Base&&) = default;
    Base& operator=(const Base&) = default;
    Base& operator=(Base&&) = default;
    virtual ~Base() = default;

    virtual void show() { std::cout << "Base " << a_ << std::endl; }

  private:
    int a_;
};
2赞 Jarod42 1/2/2017 #2

您可以创建一次类,例如

struct VirtualBase
{
      virtual ~VirtualBase() = default;
      VirtualBase() = default;
      VirtualBase(const VirtualBase&) = default;
      VirtualBase(VirtualBase&&) = default;
      VirtualBase& operator = (const VirtualBase&) = default;
      VirtualBase& operator = (VirtualBase&&) = default;
};

然后遵循零法则:

class Base : VirtualBase
{
public:
    Base(): a_(42) {}
    virtual void show() { std::cout << "Base " << a_ << std::endl; }

  private:
    int a_;
};

评论

0赞 iammilind 1/2/2017
很好的建议,我正要写这个答案。但不确定,当涉及多重继承时,它的命运会是什么。虚拟继承不是安全吗?VirtualBase
0赞 Jarod42 1/2/2017
@iammilind:虚拟继承比简单继承成本高,所以除非需要,否则我会坚持正常继承。
0赞 n. m. could be an AI 1/2/2017
@iammilind虚拟继承或不继承都是安全的。