【问题标题】:Does "The Rule of Zero" also apply for classes with virtual methods?“零规则”是否也适用于具有虚拟方法的类?
【发布时间】:2014-03-05 10:13:03
【问题描述】:

我发现The rule of Zero 也提到了Peter Sommerlads Slides (p.32) 非常引人注目。

虽然,我似乎记得有一个严格的规则,一个必须定义析构函数 virtual如果该类有 虚拟成员,实际上是派生的。

struct Base {
    virtual void drawYourself();
    virtual ~Base() {}
};
struct Derived : public Base {
    virtual void drawYourself();
};

析构函数的主体甚至可能是空的(它只需要 vtbl 中的条目)。

我似乎记得在使用层次结构时

int main() {
    Base *obj = new Derived{};
    obj->drawYourself(); // virtual call to Derived::drawYourself()
    delete obj; // Derived::~Derived() _must_ be called
}

那么重要的是delete obj 调用正确的析构函数。如果我完全省略析构函数定义,它不会变为虚拟,因此会调用错误的 d'tor 是否正确?

struct Base {
    virtual void drawYourself();
    // no virtual destructor!
};

这引出了我的最后一个问题:

  • “零规则”在具有虚拟方法的层次结构中是否也适用
  • 或者在这些情况下我需要定义虚拟析构函数吗?

编辑:正如我在回答中被提醒的那样,我的 1sr 版本的问题有错误的假设。相关的(虚拟)析构函数位于Base,而不是Derived。但我的问题仍然存在:我是否需要声明(虚拟)析构函数?

【问题讨论】:

  • 1) 当然。 2)当你认为你要多态地delete时,你需要定义一个虚拟析构函数。
  • 该死的。我发现“零规则”非常引人注目,因为如果应用得当,到目前为止它没有例外(与 C++ 中的所有其他内容不同)。现在这个希望消失了...... ;-)
  • = defaulting 特殊会员不以任何方式违反 Ro0。重要的部分是,您不必自己实现它们的功能,而是从处理单一职责的unique_ptrvector 等构建块派生它。 tbh,即使你有它,没有= default,对于析构函数来说也很好——因为你不需要手动在其中做任何事情。一切仍由相应成员的析构函数处理。
  • 值得注意的是std::shared_ptr<Base>,如果从Derived*(或make_shared<Derived>)构造,将通过调用Derived::~Derived()进行清理,并且不需要Base::~Base()是虚拟的。跨度>
  • @towi:std::shared_ptr 是正确的。在std::unique_ptr 中,您不会得到这种行为,因为自定义删除器是类型的一部分(即所有std::unique_ptr<Base, ThisDeleterType> 都会以相同的方式删除对象)。所以unique_ptr 自定义删除器确实对多态性没有用处。

标签: c++ c++11 destructor virtual-destructor rule-of-zero


【解决方案1】:

它实际上是必须声明为虚拟的基本析构函数,它在派生类中自动为虚拟:

struct Base {
    virtual void drawYourself();
    virtual ~Base() = default;
};

struct Derived : public Base {
    virtual void drawYourself();
};

但除此之外,零规则仍然有效。

如果您按照自己的方式进行操作,或者如果您省略了 virtual 析构函数,那么当 delete通过基指针调用派生对象时,您只会得到未定义的行为。

【讨论】:

  • 愚蠢的我。让我们修改我的问题。
  • 你可能想把“constructor”改成“destructor”
  • 不是“除此之外” - 这仍然属于 = default 的 Ro0。
  • @Xeo 是的,也许吧,但仍然必须记住它。 并且在它前面写上virtualAnd 仅适用于具有另一个虚拟方法的类。如果没有派生类,And 可以省略它(实际上这没有任何意义)。无论如何,仍然需要解释原因。
猜你喜欢
  • 1970-01-01
  • 2023-04-02
  • 2016-08-13
  • 2014-06-15
  • 2019-12-16
  • 2020-10-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多