关于C++:每个类都应该有一个虚拟析构函数吗?

Should every class have a virtual destructor?

Java和C语言支持类不能被用作基类的概念,EDCX1引用0和EDCOX1 1个关键字。但是在C++中,没有一个好的方法来防止一个类被派生出来,这会使类的作者陷入一个两难境地,每个类都有一个虚拟析构函数吗?

编辑:因为C++ 11不再是真的,所以可以指定一个类是EDCOX1,0是。

一方面,给一个对象一个虚拟析构函数意味着它将有一个vtable,因此为vptr每个对象消耗4(或8)个额外的字节。

另一方面,如果以后有人从这个类派生,并通过指向基类的指针删除派生类,那么程序将被错误定义(由于没有虚拟析构函数),坦率地说,为每个对象优化指针是荒谬的。

在握紧的手上有一个虚拟析构函数(有争议的)广告说,这种类型是打算多态使用。

有些人认为你需要一个明确的理由不使用虚拟析构函数(就像这个问题的潜台词一样),而另一些人则认为只有当你有理由相信你的类是从中派生出来时,你才应该使用它们,你认为呢?


每个抽象类都应该有一个,

  • 受保护的析构函数,或,
  • 虚拟析构函数。

如果您有一个公共的非虚拟析构函数,那就不好了,因为它允许用户通过该指针删除派生对象。因为我们都知道,这是未定义的行为。

对于不打算通过指向类的指针删除的类,没有任何理由使用虚拟析构函数。它不仅会浪费资源,更重要的是它会给用户一个错误的提示。想想给std::iterator一个虚拟的析构函数会有什么糟糕的感觉。


问题是,您真的想强制执行有关如何使用类的规则吗?为什么?如果一个类没有虚拟析构函数,那么任何使用该类的人都知道它不是有意从中派生出来的,并且如果您仍然尝试它,会有什么限制。这还不够好吗?

或者,如果有人敢做你没有预料到的事情,你是否需要编译器抛出一个硬错误?

如果您打算让人们从类中派生,请给类一个虚拟析构函数。否则不要这样做,并假定任何使用您的代码的人都足够聪明,能够正确地使用您的代码。


不!只有通过基类指针删除派生类的对象时,才使用虚拟析构函数。如果您的类不打算作为这个场景中的基础,那么不要将析构函数设为虚拟的——您将发送错误的消息。


查看Herb Sutter的这篇文章:

准则4:基类析构函数应该是公共的和虚拟的,或者是受保护的和非虚拟的。


我不同意这个一般性的问题。不是每个班都需要一个。如果您知道永远不应该从继承类,那么就不需要产生较小的开销。但是如果有机会的话,站在安全的一边,把一个放进去。


当基类包含至少一个纯虚函数时,它将成为抽象类。如果基没有虚拟析构函数,并且派生(派生自基)没有,那么可以通过派生对象指针而不是通过基对象指针安全地销毁派生对象。


我要补充的是,有时当我在父类或子类中忘记了一个虚拟的时候,我会在析构函数上挠头一段时间而不被调用。不过,我想我现在知道要找那个了。:)

有人可能会说,有时父类在其析构函数中做了一些子类不应该做的事情…但这可能是继承结构出现问题的一个指标。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
include<iostream> using namespace std;

class base {
    public: base() {
        cout <<"In base class constructor" << endl;
    }

    virtual ~base() {
        cout <<"in base class destuctor" << endl;
    }
};

class derived : public base {
    public: derived() {
        cout <<"in derived class constructor" << endl;
    }

    ~derived() {
        cout <<"in derived class destructor" << endl;
    }
};

int main() {
    base *b; // pointer to the base
    class b = new derived; // creating the derived class object using new
    keyword;
    delete b;
    return 0;
}