虚拟继承中的析构函数
Posted
技术标签:
【中文标题】虚拟继承中的析构函数【英文标题】:Destructor in virtual inheritance 【发布时间】:2016-08-14 03:14:33 【问题描述】:class Base;
class D1:virtual public Base;
class D2:virtual public Base;
class DD:public D1,public D2;
int main()
Base *pBase=new DD;
delete pBase;
这会导致崩溃,但我修改如下:
class Base
public:
virtual ~Base();
;
class D1:virtual public Base
public:
virtual ~D1()
;
class D2:virtual public Base
public:
virtual ~D2()
;
class DD:public D1,public D2
;
然后,它通过了,但是默认的析构函数应该是虚拟的哑函数,不是吗?
【问题讨论】:
请不要使用 Microsoft_tmain
发布代码,除非它是 Visual C++ 特定的代码。它使其他人更难尝试您的代码,并教新手不良习惯。为你解决了这个问题。只需使用标准的int main()
。
virtual
在声明中做了什么:class D : virtual public Base
?我从未见过这种结构(这可能是我的无知......)。
@Chiel en.wikipedia.org/wiki/Virtual_inheritance,当你继承多个共享同一个基类的类时使用它。
隐式声明的析构函数不是虚拟的。
尽管如此,您的代码在 clang
和 g++
中都可以正常编译,并且在这里也不会崩溃。
【参考方案1】:
来自 C++11 规范 (ISO/IEC 14882:2011(E)),第 12.4 节析构函数 [class.dtor]:
第 4 小节:
如果一个类没有用户声明的析构函数,则析构函数被隐式声明为默认值 (8.4)。隐式声明的析构函数是其类的内联公共成员。
第 6 小节:
默认且未定义为已删除的析构函数在被 odr 使用 (3.2) 销毁其类类型 (3.7) 的对象时或在其第一次声明后显式默认时被隐式定义。
最后是第 9 小节:
析构函数可以声明为虚拟(10.3)或纯虚拟(10.4);如果在程序中创建了该类或任何派生类的任何对象,则应定义析构函数。如果一个类有一个带有虚拟析构函数的基类,那么它的析构函数(无论是用户声明的还是隐式声明的)都是虚拟的。
在最后一句强调我的。
编译器将生成一个虚拟析构函数仅如果基类有一个虚拟析构函数。如果基类没有虚拟析构函数,例如第一个示例中的Base
,那么子类将没有虚拟析构函数。如果一个类没有基类,编译器生成的析构函数将不是虚拟的。
【讨论】:
【参考方案2】:这与虚拟继承无关。
通过指向类型 T 而非最初分配的类型 D 的指针删除是未定义行为,除非类型 T 是 D 的基类并且具有虚拟析构函数。
C++14(如 N3936 草案)§5.3.5/3” ...如果要删除的对象的静态类型与其不同 动态类型,静态类型应该是要删除的对象的动态类型的基类, 静态类型应具有虚拟析构函数,否则行为未定义。
虚拟析构函数用于识别类型 D,特别是它的大小和析构函数,可能还有它的自定义释放函数(您的代码没有那个)。
回复
”默认的析构函数应该是virtual dummy function,不是吗?
不,不是。
因为 C++ 设计的一个指导原则是不用为不使用的东西付费,而另一个指导原则是让程序员控制自己,让程序员能够表达任何需要(例如,出于某种目的)内存中的二进制布局)。
仅当基类具有虚拟析构函数时,您才会获得默认的虚拟析构函数。
【讨论】:
以上是关于虚拟继承中的析构函数的主要内容,如果未能解决你的问题,请参考以下文章
C++ 虚拟析构函数 (virtual destructor)