每个班级都应该有一个虚拟的析构函数吗?

时间:2008-12-09 18:56:10

标签: c++ virtual-destructor

Java和C#支持使用finalsealed关键字不能用作基类的类的概念。但是,在C ++中,如果每个类都有一个虚拟的析构函数,那么就没有什么好的方法可以防止类的派生出于两难境地?


编辑:由于C ++ 11不再适用,您可以指定一个类为final


一方面给对象一个虚拟析构函数意味着它将具有vtable,因此vptr每个对象消耗4个(或64位机器上的8个)。

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

gripping hand 上有一个虚拟析构函数(可以说)宣告这种类型是多态的。

有些人认为你需要一个明确的理由不使用虚拟析构函数(正如this question的潜台词),而其他人则说只有当你有理由相信你的班级是派生自的想法?

8 个答案:

答案 0 :(得分:53)

每个抽象类都应该有一个

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

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

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

答案 1 :(得分:28)

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

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

如果您打算让人们从中派生,那么为该类提供一个虚拟析构函数。否则不要,并假设使用您的代码的任何人都足够聪明,可以正确使用您的代码。

答案 2 :(得分:8)

没有!仅当通过基类指针删除派生类的对象时才使用虚拟析构函数。如果您的类不打算在此场景中作为基础,请不要将析构函数设置为虚拟 - 您将发送错误的消息。

答案 3 :(得分:4)

检查this article from Herb Sutter

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

答案 4 :(得分:2)

我对一般性问题“不”。不每个类都需要一个。如果您知道该类永远不应该继承,那么就不需要承担轻微的开销。但如果有机会,请保持安全,并将其放在那里。

答案 5 :(得分:1)

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

答案 6 :(得分:0)

我会补充一点,有些时候,当我在父母或子女班级忘记虚拟时,有一段时间我在破坏者没有被召唤的情况下划了一会儿。我想我现在知道要找那个了。 :)

有人可能会争辩说,有些时候父类会在析构函数中做一些孩子不应该做的事情......但这可能表明你的继承结构有问题。

答案 7 :(得分:-4)

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;
}