虚拟继承中的析构函数

时间:2016-04-21 05:56:09

标签: c++ destructor delete-operator virtual-inheritance virtual-destructor

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{
};

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

2 个答案:

答案 0 :(得分:4)

从C ++ 11规范(ISO / IEC 14882:2011(E)),第12.4节Destructors [class.dtor]:

第4小节:

  

如果一个类没有用户声明的析构函数,则析构函数被隐式声明为默认值(8.4)。隐式声明的析构函数是其类的内联公共成员。

第6小节:

  

当使用odr-used(3.2)来销毁其类类型(3.7)的对象或在第一次声明后显式默认为默认值时,默认定义了一个默认的析构函数并且未定义为已删除的析构函数。

最后第9小节:

  

析构函数可以声明为虚拟(10.3)或纯虚拟(10.4);如果在程序中创建了该类或任何派生类的任何对象,则应定义析构函数。如果一个类有一个带有虚析构函数的基类,那么它的析构函数(无论是用户还是隐式声明)都是虚拟的。

强调我的最后一句话。

如果基类具有虚拟析构函数,编译器将仅生成虚拟析构函数 。如果基类没有虚拟析构函数,例如第一个示例中的Base,那么子类将不具有虚拟析构函数。如果一个类没有基类,则编译器生成的析构函数将不是虚拟的。

答案 1 :(得分:3)

这与虚拟继承无关。

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

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

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

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

RE

  

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

不,不是。

因为C ++设计的一个指导原则是你不为你不使用的东西买单,而另一个指导原则就是让程序员掌控,能够表达所需要的东西(例如用于目的)内存中的二进制布局。)

只有在基类具有虚拟析构函数时才会获得默认的虚拟析构函数。