为什么基类不强制使用 (C++) 虚拟析构函数

问题描述 投票:0回答:4

默认情况下,析构函数不是虚拟的,这样在不需要时不会造成伤害,这很好。

但是在基类派生类场景中,有没有没有虚拟析构函数的用例?如果不是,如果一个类派生自定义了公共非虚拟析构函数(或没有析构函数)的基类,编译器可能会抱怨(是否有意义)。而不仅仅是警告它。

c++ oop destructor theory
4个回答
12
投票

您的想法的问题在于,可以想象有人正在使用非虚拟基类析构函数作为优化(如果您永远不会通过基类指针进行销毁,那么缺少的虚拟不会伤害您,并且仍然避免了 vtable 条目)。

既然可以使用,那就是允许的。我认为可选的编译器警告可能是个好主意,但不是语言规范中的内容。


8
投票

因为拥有非虚拟析构函数是完全有效的。例如,如果子类仅设计为堆栈分配,则不需要虚拟析构函数。当一个类只应该是一个装饰器时,为什么要求客户端拥有所有的 vtbl 机制?

当一个类要从私有继承时(按其实现),拥有虚拟析构函数也没有什么意义。

总而言之,析构函数通常应该是公共的、虚拟的或受保护的,除非一个类不是基类。


5
投票

仅当您通过

delete
执行对象的多态销毁时才需要虚拟析构函数。反过来,这立即意味着动态分配
new
-ed)对象。

如果不动态分配对象,则不需要虚拟析构函数。当不需要基类中的虚拟析构函数时,这立即提供了无限的用例源。

如果动态分配对象,但从不以多态方式销毁它们,则不需要虚拟析构函数。当不需要基类中的虚拟析构函数时,这会添加另一组用例。


2
投票

您的建议存在不同的问题,其中第一个问题已经在其他答案中处理过:如果您打算通过指向基的指针进行删除,则只需要虚拟析构函数(一般建议是提供公共虚拟析构函数或受保护的非虚拟析构函数,因为这会禁止通过基类进行删除)。

还有另一个问题,当编译器看到一个类定义时,它不可能知道它是否会被派生。考虑是否在翻译单元中实现基类。稍后您将从课程中派生。如果该派生意味着将构造函数设为虚拟,则必须重新编译基类转换,否则程序中的 ODR(单一定义规则)将被破坏。

如果您添加其他翻译单元,情况会变得更糟。每当您包含来自翻译单元的头文件时,您都将被迫“手动”包含至少一个头文件,其中定义了该类的派生对象(增加耦合),否则编译器将再次生成不同的定义对于该翻译单元中的单个类(与定义派生类的翻译单元相比),再次破坏了 ODR。 问题在于编译器只能看到您项目的部分视图,无法从它所看到的内容中真正推断出您需要/想要什么。

© www.soinside.com 2019 - 2024. All rights reserved.