我对大多数 OOP
理论有深刻的理解,但让我很困惑的一件事是虚拟析构函数。
我认为析构函数总是被调用,不管是什么,对于链中的每个对象。
你打算什么时候把它们变成虚拟的,为什么?
原文由 Lodle 发布,翻译遵循 CC BY-SA 4.0 许可协议
我对大多数 OOP
理论有深刻的理解,但让我很困惑的一件事是虚拟析构函数。
我认为析构函数总是被调用,不管是什么,对于链中的每个对象。
你打算什么时候把它们变成虚拟的,为什么?
原文由 Lodle 发布,翻译遵循 CC BY-SA 4.0 许可协议
我建议: 如果一个类或结构不是 final
,你应该为它定义虚拟析构函数。
我知道这看起来像是一种过度警惕的矫枉过正,成为一个经验法则。但是,这是确保从您的类派生的人在使用基指针删除时不会有 UB 的唯一方法。
Scott Meyers 在下面引用的 Effective C++ 中的建议很好,但不足以确定。
如果一个类有任何虚函数,它应该有一个虚析构函数,并且那些不是设计为基类或不是设计为多态使用的类不应该声明虚析构函数。
例如,在下面的程序中,基类 B 没有任何虚函数,因此按照 Meyer 的说法,您不需要编写虚析构函数。但是,如果您没有,您在下面有 UB:
#include <iostream>
struct A
{
~A()
{
std::cout << "A::~A()" << std::endl;
}
};
struct B
{
};
struct C : public B
{
A a;
};
int main(int argc, char *argv[])
{
B *b = new C;
delete b; // UB, and won't print "A::~A()"
return 0;
}
原文由 Özgür Murat Sağdıçoğlu 发布,翻译遵循 CC BY-SA 4.0 许可协议
3 回答2k 阅读✓ 已解决
2 回答3.9k 阅读✓ 已解决
2 回答3.2k 阅读✓ 已解决
1 回答3.2k 阅读✓ 已解决
1 回答2.7k 阅读✓ 已解决
3 回答3.4k 阅读
1 回答3.3k 阅读
当您可能通过指向基类的指针删除派生类的实例时,虚拟析构函数很有用:
在这里,您会注意到我没有将 Base 的析构函数声明为
virtual
。现在,让我们看一下以下代码段:Since Base’s destructor is not
virtual
andb
is aBase*
pointing to aDerived
object,delete b
has undefined行为:在大多数实现中,对析构函数的调用将像任何非虚拟代码一样被解析,这意味着将调用基类的析构函数而不是派生类的析构函数,从而导致资源泄漏。
总而言之,当要对基类进行多态操作时,请始终制作基类的析构函数
virtual
。如果要防止通过基类指针删除实例,可以使基类析构函数受保护且非虚拟;这样做,编译器不会让你在基类指针上调用
delete
。您可以在 Herb Sutter 的这篇文章 中了解有关虚拟性和虚拟基类析构函数的更多信息。