我发现零规则,正如Peter Sommerlad的幻灯片(第32页)中所提到的一样,非常有说服力。
尽管如此,我似乎记得有一个严格的规则,即如果类具有虚成员并且实际上是派生类,则必须定义析构函数为虚函数。
如果
这让我想到了我的最后一个问题:
尽管如此,我似乎记得有一个严格的规则,即如果类具有虚成员并且实际上是派生类,则必须定义析构函数为虚函数。
struct Base {
virtual void drawYourself();
virtual ~Base() {}
};
struct Derived : public Base {
virtual void drawYourself();
};
析构函数的主体甚至可以为空(只需要在虚函数表中有条目即可)。
我似乎记得在使用继承层次结构时
int main() {
Base *obj = new Derived{};
obj->drawYourself(); // virtual call to Derived::drawYourself()
delete obj; // Derived::~Derived() _must_ be called
}
如果
delete obj
调用正确的析构函数是很重要的。如果我完全省略了析构函数定义,那么它将不会变成虚函数,因此错误的析构函数将被调用吗?struct Base {
virtual void drawYourself();
// no virtual destructor!
};
这让我想到了我的最后一个问题:
- “零规则”在具有虚拟方法的层次结构中是否也适用?
- 还是在这些情况下需要定义虚拟析构函数?
编辑:正如我在回答中被提醒的那样,我对问题的第一版做出了错误的假设。相关(虚拟)析构函数在Base
中,而不是Derived
。但我的问题仍然存在:我需要声明(虚拟)析构函数吗?
delete
操作时,您需要定义一个虚析构函数。= default
特殊成员函数并不以任何方式违反Ro0,重要的是,您不需要自己实现它们的_功能_,而是从构建块(如unique_ptr
和vector
)派生出来,这些构建块处理单个职责。老实说,即使没有= default
,析构函数也可以正常工作-因为您没有在其中手动执行任何操作。一切仍由适当成员的析构函数处理。 - XeoDerived*
(或make_shared<Derived>
)构造std::shared_ptr<Base>
,则其将通过调用Derived::~Derived()
进行清理,并且不需要将Base::~Base()
声明为虚函数。 - Ben Voigtstd::shared_ptr
是正确的。在std::unique_ptr
中,你不会得到这种行为,因为自定义删除器是类型的一部分(即所有的std::unique_ptr<Base, ThisDeleterType>
将以相同的方式删除对象)。因此,unique_ptr
自定义删除器对于多态性并不实用。 - Ben Voigt