C++析构函数作为虚拟函数

C++ destructors as virtual functions?

本文关键字:虚拟 函数 析构函数 C++      更新时间:2023-10-16

我最近刚刚读到,将C++析构函数实现为虚拟函数是一种很好的做法[1]。为什么会这样?这是一种普遍的良好做法吗?如果不是,在什么条件/情况下,析构函数将成为虚拟函数?

参考

  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完成的。