C++析构函数作为虚拟函数
C++ destructors as virtual functions?
我最近刚刚读到,将C++析构函数实现为虚拟函数是一种很好的做法[1]。为什么会这样?这是一种普遍的良好做法吗?如果不是,在什么条件/情况下,析构函数将成为虚拟函数?
参考
- https://www.blackhat.com/presentations/bh-usa-07/Afek/Whitepaper/bh-usa-07-afek-WP.pdf
Herb Sutter在他的文章"虚拟性"中详细讨论了这个主题。准则#4指出:"基类析构函数应该是公共的和虚拟的,或者是受保护的和非虚拟的。"
如果你的类不是设计或打算用作基类的,那么就没有理由用虚拟析构函数来声明它。
如果基类有一个析构函数,并且它不是虚拟的,那么如果在基类的指针上调用delete,则不会调用任何子类的析构函数。
这可能导致内存泄漏。
class Shape
{
public:
Shape()
{
cout << "Shape constructor called" << endl;
}
// This destructor should be virtual!
~Shape()
{
cout << "~Shape destructor called" << endl;
}
};
class Triangle : public Shape
{
public:
Triangle()
{
cout << "Triangle constructor called" << endl;
}
~Triangle()
{
cout << "Triangle destructor called" << endl;
}
}
int main(int argc, char* argv[])
{
Shape* pShape = new Triangle();
cout << "About to call delete" << endl;
delete pShape;
}
这将导致:
名为
的三角形构造函数名为
的形状构造函数即将呼叫删除
名为
的形状析构函数
所有应该在三角形析构函数中释放的资源现在都泄漏了。
来自Scott Meyers的Effective C++-"为基类提供虚拟析构函数的规则仅适用于多态基类-适用于设计为允许通过基类接口操作派生类类型的基类。"
很可能,如果基类中有任何虚拟函数,那么基类析构函数必须是虚拟的。
未设计为基类或未设计为多态使用的类不应声明虚拟析构函数
当你的类有一个虚拟析构函数时,你可以确保派生类中的析构函数会被调用。
可以说,如果你的整个类层次结构都是POD或没有析构函数可以做,那么你可能会因为没有虚拟析构函数而逃脱惩罚。然而,只要您想从类派生其他类,并且想通过对基的指针/引用以多态方式使用它们,那么无论如何都会有虚拟函数,因此添加虚拟析构函数几乎没有开销,而且您永远不知道谁将继承自您。只要任何派生类都需要一个非平凡的析构函数,并且可以通过指向基的指针引用,就必须有一个虚拟析构函数。
经验法则:如果您有任何虚拟函数,请添加一个虚拟析构函数。
(这里的重点是,如果你有no虚拟函数,那么就没有办法以多态的方式使用派生类,所以需要非平凡破坏的私生子类通过基类指针删除的可能性会更小。这仍然可以做到,只是可能性更小。)
http://blogs.msdn.com/b/oldnewthing/archive/2004/05/07/127826.aspx
在这个时代,我认为你应该让所有的方法都是虚拟的,然后想想哪些方法不需要
好吧,是的,我大部分OOP都是用Java完成的。
- C++无法定义虚拟函数 OUTER 类和头文件
- 用常见虚拟函数实现的任意组合来实现派生类的正确方法是什么
- 尝试将unique_ptrs推送到向量时使用纯虚拟函数错误
- 有没有比在库中添加一个并非由所有派生类实现的新虚拟函数更好的设计实践
- 类型擦除的std::function与虚拟函数调用的开销
- 重写虚拟函数和继承
- 用纯虚拟函数兜圈子
- 为什么使用存储在虚拟方法表中的地址调用虚拟函数的函数会返回垃圾?
- 禁止子函数调用父级的抽象(或虚拟)函数
- 无法在子类中使用虚拟函数C++
- 无法在派生对象上运行虚拟函数
- 我可以调用从 main() 覆盖的虚拟函数吗?
- 在 C++ 中将函数获取和设置为虚拟函数
- 使用在堆栈上创建的对象调用虚拟函数
- 为什么在这种情况下不调用我的虚拟函数实现?
- 在C++中使虚拟函数私有化
- 模板继承类中的虚拟函数
- 为什么构造函数的虚拟函数调用有时有效,但其他调用却无效
- doxygenc++虚拟函数和实现
- 如何从派生类函数中调用虚拟函数