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{
};
然后,它通过,但默认的析构函数应该是虚拟虚函数,不是吗?
答案 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 ++设计的一个指导原则是你不为你不使用的东西买单,而另一个指导原则就是让程序员掌控,能够表达所需要的东西(例如用于目的)内存中的二进制布局。)
只有在基类具有虚拟析构函数时才会获得默认的虚拟析构函数。