先放结论:在的!
而且与声明的先后顺序有关
为什么有这个疑问呢?因为析构函数的名字不一样啊......(好吧,是我too young了)
实验代码的继承关系如下:
class fa{
public:
fa(){}
virtual ~fa(){cout << "des fa" << endl;}
virtual show(){cout << "fa show" << endl;}
virtual wohs(){cout << "fa wohs" << endl;}
};
class son : public fa{
public:
son(){}
virtual ~son(){cout << "des son" << endl;}
virtual show(){cout << "son show" << endl;}
virtual wohs(){cout << "son wohs" << endl;}
};
先对一个对函数指针改改名,方便定义:
typedef void(* func)(void);
虽然c++标准明确规定不能获取构造函数和析构函数的地址,但是这一切在指针的面前都是浮云(论指针的可怕之处......)
int main()
{
son boy;
func fff;
fff = (func)*(int *)((char*)(*(int *)&boy));
/*
vptr在实例对象地址的开头,
跟着这个地址走到虚函数表,
获取表中的函数地址,
跟着这个地址走,来到函数的开头,
把这个地址交给fff
*/
fff();
return 0;
}
然后成功地发现析构函数调用了两次,一次是fff调的,一次是return时调的,至于fff是什么类型的函数指针?随意,反正到最后
汇编时都会变成:call 析构函数地址
我们来试试虚函数表的下一个函数,即:fff = (func)*(int *)((char*)(*(int *)&boy + 4));
怎么还是析构......(经过试验,虚析构函数占两个位,不知道为什么......)
那再试下下一个,下两个......
好,子类的虚函数show出来了
子类的虚函数wohs也出来了
可见虚析构函数真的在虚函数表,而且和声明顺序有关(这个可以自己试验下)
然后还有个问题,既然子类的虚函数表中只有子类虚析构函数,那它怎样析构父类呢?父类的析构函数又在哪呢?
老规矩,反汇编走起
下一部,进入到子类的析构函数:
然后惊喜地发现,在子类的析构函数中包含着对父类析构函数的调用
总结:虚析构函数的地址存在于虚函数表中,和普通虚函数别无二致,同时也会像普通的虚函数一样进行覆盖
虽然父子的析构函数名字不一样,但是他们占同一个坑(即父子析构函数在虚函数表中的位置是一样的,否则就不存在多态了)
析构时,到特定的坑中调用该类型的析构函数,其析构函数中又嵌套了很多对父类的析构函数的调用