C++ 接口的虚拟析构函数

C++ 接口的虚拟析构函数,c++,polymorphism,C++,Polymorphism,接口是否需要虚拟析构函数,或者自动生成的析构函数可以吗?例如,以下两个代码段中哪一个是最好的,为什么?请注意,这些都是全班的。没有其他方法、变量等。在Java语言中,这是一个“接口” 或者 由于“不是我要找的”而编辑答案: 每条路线的具体后果是什么。请不要给出含糊的回答,比如“它不会被正确破坏”。请确切地告诉我会发生什么事。我有点像个装配迷 编辑2: 我很清楚“virtual”标记意味着如果通过指向派生的指针删除析构函数,则不会调用析构函数,但是(我认为)这个问题最终归结为“省略该析构函数是否安

接口是否需要虚拟析构函数,或者自动生成的析构函数可以吗?例如,以下两个代码段中哪一个是最好的,为什么?请注意,这些都是全班的。没有其他方法、变量等。在Java语言中,这是一个“接口”

或者

由于“不是我要找的”而编辑答案:


每条路线的具体后果是什么。请不要给出含糊的回答,比如“它不会被正确破坏”。请确切地告诉我会发生什么事。我有点像个装配迷

编辑2:

我很清楚“virtual”标记意味着如果通过指向派生的指针删除析构函数,则不会调用析构函数,但是(我认为)这个问题最终归结为“省略该析构函数是否安全,因为它真的很小吗?”

编辑3:


我的第二次编辑完全是错误的和虚假的信息。有关更多信息,请阅读实际聪明人的评论。

否。。。虚拟析构函数不是自动生成的。您必须在基类中明确声明它们。 但是不需要为基类的子类声明虚析构函数。这是由编译器完成的。 编译器还将确保以相反的构造顺序(从派生到基)调用析构函数

如果你没有虚拟析构函数

delete b;

会导致内存泄漏(整数字段至少有4个字节),因为它只会破坏
Base
,而不会破坏
Derived
。虚拟性确保派生类也被销毁。您不必在
Derived
中声明虚拟构造函数,这将由编译器推断,如果您在
Base
中声明虚拟析构函数,如果您希望人们尝试通过父类的指针或引用删除派生类的对象,则应使用虚拟析构函数。如果是这种情况,那么如果没有虚拟析构函数,派生类将永远不会被正确析构函数

比如说,

Derived::~Derived() { // important stuff }
Base *foo = new Derived();
delete foo;

如果Base中没有虚拟析构函数,派生的析构函数将永远不会被调用,因此重要的内容将永远不会发生。

考虑以下情况:

   Base *Var = new Derived();
   delete Var;

您需要虚拟析构函数,否则当您删除
Var
时,将永远不会调用派生类的析构函数。

通常,析构函数应该是(1)公共和虚拟的,或者(2)受保护和非虚拟的

假设您从未期望任何人通过接口指针删除类实例,那么受保护的非虚拟析构函数是100%安全的


如果有人试图删除一个接口指针(2),则会得到编译时错误。

< P>如果通过C++中的基类指针删除派生类对象,结果是未定义的行为。UB是您真正想要避免的东西,所以您必须给基类一个虚拟析构函数。引用C++标准,第5.3.5节:

如果操作数的静态类型为 与它的动态类型不同的是 静态类型应为 操作数的动态类型和 静态类型应具有虚拟属性 析构函数或该行为是 未定义


主要回复编辑:


没有人能告诉你会发生什么,因为结果是“未定义的行为”。当您通过指向没有虚拟析构函数的基的指针删除派生类时,实现可以以任意方式分解。

它没有值得一提的析构函数。@wowus:base没有值得一提的析构函数。你不知道派生的析构函数是做什么的。你错过了关键点<代码>派生::~Derived不会被调用,除非您将Base::~Base声明为虚拟。不,它是反向调用的。
Base
中缺少虚拟析构函数意味着删除
Base*
类型的指针时,只调用
Base::~Base
。如果<代码> Base<代码>析构函数是虚的,那么派生析构函数也将被调用。@ BSARDs,如果指针是派生的,那么将调用派生的和~(?)基,析构函数是否为虚的。实际上,在这种情况下,C++所定义的情况是什么。虚拟标记并不意味着如果通过指向派生的指针删除基析构函数,则不会调用基析构函数-这种情况经常发生。相反,虚拟标记意味着,如果您通过基类类型的指针删除对象,将调用派生析构函数。@Jordan:噢,天哪,我想您是对的。“我有点程序集呆子”。这是不幸的,因为C++不涉及生成程序集。如果您想了解特定编译器如何处理它,请编译一些代码并查看输出。和-1只是对你的态度;不要问一个问题,告诉所有的回答者“你倒了”,然后否决他们。你问这个问题是有原因的,不是吗?仅供参考-一旦我弄明白了,我就取消了否决票。@wowus:很公平,地雷也没了。:)你第一句话的意思是说“毁灭者”吗?
delete b;
Derived::~Derived() { // important stuff }
Base *foo = new Derived();
delete foo;
   Base *Var = new Derived();
   delete Var;