考虑以下代码:
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;
我非常清楚使用非虚拟析构函数的危险。但上面的代码让我想知道两件事:
修改
似乎我需要澄清困扰我的事情:
上面的代码声明没有析构函数。
如果我声明一个虚函数,编译器会抱怨缺少虚拟析构函数。我的结论:如果类是多态的,我需要编写一个虚拟析构函数,如果delete p
能够正常工作。
但是,如果我声明没有虚函数(如上面的初始示例中所示),编译器不会抱怨缺少虚拟析构函数。我的结论:如果类不是多态的,我不需要编写虚拟析构函数,delete p
无论如何都能正常工作。
但最后的结论对我来说听起来很直接。这是错的吗?编译器是否应该在两种情况下都抱怨?
答案 0 :(得分:1)
关注PaulMcKenzie和KerrekSB的评论,以下是原帖中两个问题的答案:
这背景可以在C ++ 11标准的第5.3.5节中找到,该标准说:“如果要删除的对象的静态类型与其动态类型不同,则静态类型应为基础要删除的对象的动态类型的类,静态类型应具有虚拟析构函数或行为未定义。“ (Italics mine。)
答案 1 :(得分:0)
你正在进行向上转换,换句话说:类B的多态使用。如果类A没有虚拟成员,则编译器不会为类A生成VTABLE,并且它不需要虚拟析构函数(请注意如果没有使用多态,你的upcasting没有任何意义)。如果类A声明了虚拟成员,则由编译器生成VTABLE,在这种情况下,您应该提供虚拟析构函数。
答案 2 :(得分:0)
如果你想要多态行为,你需要在编译器中定义至少一个虚函数,应该为你的类生成v-table。
因为C ++类包含两个用于每个对象的特殊函数(构造函数和析构函数),所以它是使析构函数成为虚拟的一个很好的选择。
当您编写delete p
时,您实际上会为与指针p
关联的对象调用析构函数。如果你没有将析构函数声明为虚拟,那么你就会得到容易出错的代码。
在您声明至少一个成员函数作为虚拟编译器之前,并不希望您打算将您的类用作多态。在C ++哲学中:"你不应该支付你永远不会使用的功能"。例如。在简单的情况下,析构函数不应该是虚拟的。