我们知道在发生多态时,如果涉及到利用析构函数释放子类内存的操作,父类必须要采用虚析构,否则只会调用父类的析构函数,并不能调用子类的析构函数。但为何执行完子类析构函数,又能执行父类析构函数呢?
虚析构原理
通过reportSingleClass命令,可以看到父类析构函数添加virtual前后父类结构变化:
正常析构函数
虚析构函数
很明显,虚析构和虚函数一样,父类的虚构函数并不是在编译阶段就确定了地址的,而是产生了一个虚表指针和虚表。一开始,我认为虚表中
{dtor}
是指向的子类析构函数,但其实不是。
delete背后发生的事
参考https://blog.csdn.net/lwwl12/article/details/109365872我们可以知道,在delete对象时,{dtor}
指针其实是指向‘vector deleting destructor’
、实际上调用了'scalar deleting destructor’
函数(由编译器生成)用于delete删除对象,而不是直接指向析构函数。
delete时,析构函数的执行
在delete时,其实是调用’scalar deleting destructor’
函数,而这个函数是在虚表中,指向了子类‘scalar deleting destructor’
(因为发生了多态),所以delete就会调用子类析构函数。
另外:子类析构后,如何找到父类析构函数又析构?
其实是编译器在作怪,编译器通过将父类的析构函数写入子类析构函数之后,实现了从子类到父类的链式析构。
而且,只要父类的析构函数是虚析构函数,则子类的析构函数也是虚析构函数,子类生成的‘deleting destructor’
函数会替换虚表中父类的‘deleting destructor’
函数,和虚函数一样。