提问人:towi 提问时间:2/8/2014 最后编辑:Glorfindeltowi 更新时间:6/16/2022 访问量:1944
“零法则”是否也适用于具有虚拟方法的类?
Does "The Rule of Zero" also apply for classes with virtual methods?
问:
我发现 Peter Sommerlads 幻灯片(第 32 页)中也提到的零法则非常引人注目。
虽然,我似乎记得有一个严格的规则,即如果类具有虚拟成员并且实际上是派生的,则必须定义析构函数虚拟。
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
}
然后,调用正确的析构函数很重要。如果我完全省略析构函数定义,它就不会变成虚拟的,因此会调用错误的 d'tor,这是正确的吗?delete obj
struct Base {
virtual void drawYourself();
// no virtual destructor!
};
这就引出了我的最后一个问题:
- “零法则”在具有虚拟方法的层次结构中是否也适用
- 或者在这些情况下,我是否需要定义虚拟析构函数?
编辑:正如我在回答中被提醒的那样,我的 1sr 版本的问题有错误的假设。相关的(虚拟)析构函数在 中,而不是 。但我的问题是:我是否需要声明(虚拟)析构函数?Base
Derived
答:
8赞
user3175411
2/8/2014
#1
它实际上是必须声明为虚拟的基析构函数,并且在派生类中它会自动是虚拟的:
struct Base {
virtual void drawYourself();
virtual ~Base() = default;
};
struct Derived : public Base {
virtual void drawYourself();
};
但除此之外,零法则仍然成立。
如果你按照你的方式去做,或者如果你省略了析构函数,你只是在通过基指针连接派生对象时得到未定义的行为。virtual
delete
评论
0赞
towi
2/8/2014
傻傻的我。让我们修正一下我的问题。
3赞
Brian Bi
2/8/2014
您可能希望将“constructor”更改为“destructor”
1赞
Xeo
2/8/2014
不是“除此之外”——这仍然属于 Ro0 和 .= default
1赞
towi
2/8/2014
@Xeo是的,也许吧,但人们仍然必须记住它。并在它前面写。并且仅适用于具有其他虚拟方法的类。如果没有派生类,可以饶恕它(实际上,这毫无意义)。无论如何,人们仍然需要解释为什么。virtual
评论
delete
= default
ing 特殊成员不会以任何方式违反 Ro0。重要的部分是,您不会自己实现它们的功能,而是从处理单个责任的构建块(如 和 )中派生它。而且 tbh,即使你有它,没有 ,对于析构函数来说也很好 - 因为你不需要手动在其中做任何事情。一切仍由相应成员的析构函数处理。unique_ptr
vector
= default
std::shared_ptr<Base>
Derived*
make_shared<Derived>
Derived::~Derived()
Base::~Base()
std::shared_ptr
std::unique_ptr
std::unique_ptr<Base, ThisDeleterType>
unique_ptr