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

时间:2010-06-20 23:03:30

标签: c++ oop compiler-construction destructor theory

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

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

4 个答案:

答案 0 :(得分:12)

你的想法的问题在于,可以想象有人使用非虚基类析构函数作为优化(如果你永远不会通过基类指针销毁,那么丢失的虚拟不会伤害你,仍然避免vtable入口。)

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

答案 1 :(得分:8)

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

当一个类要私有地继承(在条件中实现)时,拥有一个虚拟析构函数也没什么意义。

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

答案 2 :(得分:5)

只有在通过delete执行对象的多态破坏时才需要虚拟析构函数。反过来,这会立即暗示动态分配new - ed)对象。

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

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

答案 3 :(得分:2)

你提出的建议有不同的问题,其中第一个已经在其他答案中得到了解答:如果你打算通过指向基地的指针删除,你只需要虚拟析构函数(一般建议是提供公共虚拟析构函数或受保护的非虚析构函数,因为它会阻止通过基类的删除。)

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

如果您在混音中添加其他翻译单元,情况会变得更糟。每当您从翻译单元中包含头文件时,您将被迫手动包含至少一个标头,其中定义了该类的派生对象(增加耦合),或者,再次,编译器会为该翻译单元中的单个类生成不同的定义(与定义派生类的翻译单元相比)再次打破ODR。

问题是编译器只有部分项目视图,无法从它看到的内容中真正推断出你需要/想要的内容。