非多态基类中的析构函数

时间:2014-04-05 12:47:05

标签: c++ polymorphism destructor

考虑以下代码:

class A {
  public:
    void fun() {}
};

class B : public A {
  public:
    void fun() {}
};

int main()
{
    A *p = new B;

    delete p;
}

类A和B不是多态的,两个类都没有声明析构函数。如果我使用g++ -Wall编译此代码,GCC编译器会愉快地编译代码。

但是如果我在A中将virtual添加到void fun(),编译器会发出以下警告:"删除具有非虚析构函数的多态类类型'A'的对象可能会导致未定义的行为& #34;

我非常清楚使用非虚拟析构函数的危险。但上面的代码让我想知道两件事:

  1. 当我根本不使用析构函数时,为什么我需要在基类中编写一个空虚拟析构函数?
  2. 如果基类不包含其他虚函数,为什么不需要空虚拟析构函数?
  3. 修改

    似乎我需要澄清困扰我的事情:

    上面的代码声明没有析构函数。

    如果我声明一个虚函数,编译器会抱怨缺少虚拟析构函数。我的结论:如果类是多态的,我需要编写一个虚拟析构函数,如果delete p能够正常工作。

    但是,如果我声明没有虚函数(如上面的初始示例中所示),编译器不会抱怨缺少虚拟析构函数。我的结论:如果类不是多态的,我不需要编写虚拟析构函数,delete p无论如何都能正常工作。

    但最后的结论对我来说听起来很直接。这是错的吗?编译器是否应该在两种情况下都抱怨?

3 个答案:

答案 0 :(得分:1)

关注PaulMcKenzie和KerrekSB的评论,以下是原帖中两个问题的答案:

  1. 该类总是有一个析构函数,即使程序员没有明确地写一个。必须声明一个空的虚拟析构函数,以防止系统自动生成非虚拟析构函数。
  2. 在提供的示例代码中,您确实需要一个虚拟析构函数,即使该类中没有其他虚函数也是如此。 GCC在这种情况下不抱怨的事实可能是编译器中的一个错误(或者至少是一个缺点)。
  3. 这背景可以在C ++ 11标准的第5.3.5节中找到,该标准说:“如果要删除的对象的静态类型与其动态类型不同,则静态类型应为基础要删除的对象的动态类型的类,静态类型应具有虚拟析构函数或行为未定义。“ (Italics mine。)

答案 1 :(得分:0)

你正在进行向上转换,换句话说:类B的多态使用。如果类A没有虚拟成员,则编译器不会为类A生成VTABLE,并且它不需要虚拟析构函数(请注意如果没有使用多态,你的upcasting没有任何意义)。如果类A声明了虚拟成员,则由编译器生成VTABLE,在这种情况下,您应该提供虚拟析构函数。

答案 2 :(得分:0)

如果你想要多态行为,你需要在编译器中定义至少一个虚函数,应该为你的类生成v-table。

因为C ++类包含两个用于每个对象的特殊函数(构造函数和析构函数),所以它是使析构函数成为虚拟的一个很好的选择。

  1. 当您编写delete p时,您实际上会为与指针p关联的对象调用析构函数。如果你没有将析构函数声明为虚拟,那么你就会得到容易出错的代码。

  2. 在您声明至少一个成员函数作为虚拟编译器之前,并不希望您打算将您的类用作多态。在C ++哲学中:"你不应该支付你永远不会使用的功能"。例如。在简单的情况下,析构函数不应该是虚拟的。