虚拟继承中的析构函数

Destructor in virtual inheritance

本文关键字:析构函数 继承 虚拟      更新时间:2023-10-16
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{
};

然后,它通过了,但默认析构函数应该是虚拟虚拟函数,不是吗?

根据 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(,则子类将没有虚拟析构函数。如果一个类没有基类,编译器生成的析构函数将不是虚拟的。

这与虚拟继承无关。

通过指针删除类型 T 而不是最初分配的类型 D 是未定义的行为,除非类型 T 是 D 的基类并且具有虚拟析构函数。

C++14(如N3936草案(§5.3.5/3

">...如果要删除的对象的静态类型与其 动态类型,静态类型应是要删除的对象的动态类型的基类和 静态类型应具有虚拟析构函数或行为未定义。

虚拟析构函数用于标识类型 D,特别是其大小和析构函数,可能还有其自定义释放函数(您的代码没有该函数(。


"> 默认析构函数应该是虚拟虚拟函数,不是吗?

不,不是。

因为C++设计的一个指导原则是你不为不使用的东西付费,另一个指导原则是让程序员控制,能够表达任何需要的东西(例如,为了内存中的二进制布局(。

仅当基类具有虚拟析构函数时,才会获得默认虚拟析构函数。