接口是否需要虚拟析构函数,或者自动生成的是否正常?例如,以下两个代码段中哪一个最好,为什么?请注意,这些是整个班级。没有其他方法,变量等。在Java中,这是一个“接口”。
class Base
{
public:
virtual void foo() = 0;
virtual ~Base() {}
};
... OR
class Base
{
public:
virtual void foo() = 0;
~Base() {} // This line can be omitted, but included for clarity.
};
编辑因为“不是我想要的”答案:
每条路线的确切后果是什么。请不要给出模糊的答案,例如“它不会被破坏”。请告诉我到底会发生什么。我有点装配书呆子。
编辑2:
我很清楚“虚拟”标签意味着如果通过指向派生的指针删除析构函数将不会被调用,但是(我认为)这个问题最终归结为“省略该析构函数是否安全,因为它真的微不足道吗?“
编辑3:
我的第二次编辑只是完全错误和虚假信息。请阅读实际聪明人的评论以获取更多信息。
答案 0 :(得分:13)
考虑以下情况:
Base *Var = new Derived();
delete Var;
您需要虚拟析构函数,否则当您删除Var
时,将永远不会调用派生类的析构函数。
答案 1 :(得分:7)
如果在C ++中通过基类指针删除派生类对象,则结果是未定义的行为。 UB是你真正想要避免的,所以你必须给基类一个虚拟析构函数。引用C ++标准,第5.3.5节:
如果操作数的静态类型是 不同于它的动态类型 static类型应该是基类 操作数的动态类型和 静态类型应具有虚拟 析构函数或行为是 未定义。
答案 2 :(得分:3)
如果您希望人们尝试通过父类的指针或引用来删除派生类的对象,则应该使用虚拟析构函数。如果是这种情况,那么在没有虚拟析构函数的情况下,派生类将永远不会被正确销毁。
例如,
Derived::~Derived() { // important stuff }
Base *foo = new Derived();
delete foo;
如果没有Base中的虚拟析构函数,Derived的析构函数永远不会被调用,因此重要的东西永远不会发生。
答案 3 :(得分:3)
主要回复编辑:
没有人能告诉你会发生什么,因为结果是“未定义的行为”。当您通过指向没有虚析构函数的基类的指针删除派生类时,实现可以通过多种方式自由分解。
答案 4 :(得分:2)
一般来说,析构函数应该是(1)公共和虚拟,或(2)受保护和非虚拟。
假设您从未期望任何人通过接口指针删除类实例,受保护的非虚拟析构函数是100%安全的。
如果有人试图删除case(2)中的接口指针,则会出现编译时错误。
答案 5 :(得分:0)
否...不会自动生成虚拟析构函数。您必须在基类中明确声明它们。 但是你不需要为Base的子类声明你的析构函数是虚拟的。这是由编译器完成的。 编译器还将确保以相反的构造顺序(从派生到基础)调用析构函数。
public class Base
{
//...
}
public class Derived
{
int i = 0;
//...
}
//...
Base* b = new Derived();
如果您没有虚拟析构函数
delete b;
会导致内存泄漏(整数字段至少为4个字节),因为它只会破坏Base
而不会破坏Derived
。虚拟性也确保派生类也被销毁。您不必在Derived
中声明虚拟构造函数,如果您在Base
中声明了虚拟析构函数,这将由编译器推断。