虚析构和虚表

   首先给出调用方式

Base* b = new child;

child* c = new child;

         第一种情况:基类和子类的析构函数都不是虚函数。

   此种情况下,基类和子类各自调用自己的析构函数。如果直接delete b,则会导致内存空间泄露。(第一句里面,先是new了一个child,child的地址空间包含了[base]+[other]两部分,然后强制赋值给b。由于b是Base类型,无法接收[other]部分,导致[other]指向不明。如果直接调用delete b,则只会释放掉b指向的[base]部分,而new出来的[other]部分则无法释放)

         第二种情况:基类和子类的析构函数都是虚函数

         为Base和child增加虚析构,可以看出b和c都增加了虚表。C的虚表指向自己。b的虚表指向了c的析构函数。因此,调用delete b首先是调用child的析构函数。由于子类析构时会调用基类的析构函数,child的析构函数调用完成后会调用base的析构函数。将new出来的内存空间完全释放。

      值得注意的是,虚表是一个指向“一系列重定向函数入口地址”的指针,也就是说,不管虚表内有几个虚函数,虚表占用的内存空间一定是4字节。比如上图中size_c等于12(C自己的int变量c,从base那里继承来的int变量b,虚表)。

      有趣的是,虽然Base的大小为8字节(自身int变量b,虚表),但实例b为指向子类的指针,跟踪后发现,图2中多出了蓝色框中的内容,我猜大概是为了维护指向的子类信息。而且child加上了[],让我想到了间接寻址或偏移量。如果Base类的实例b自带了子类的信息,为什么不能直接获取子类的类型,还需要Child* p = dynamic_cast(Base*)转换? 

原文地址:https://www.cnblogs.com/hgwang/p/5872084.html