虚函数浅析
0. 原理简述
父类中如果存在虚函数,类中会隐含一个虚函数指针,指向一个虚函数表,表中存储了父类的所有虚函数入口地址。子类继承父类,会复制一份虚指针和虚表。此时如果子类重写了父类的虚函数,会将重写的虚函数入口地址更新到虚表中。若父类指针指向了子类,并且调用虚函数,会在我们更新的虚表里找虚函数入口地址,此时已经是子类重写的虚函数了。
1. 多个对象指向同一个虚函数表

2. 普通对象和指针对象调用虚函数
为了更好理解普通对象和指针对象,先观察子类的普通对象和指针对象调用虚函数,普通对象类型 在编译期直接查到虚函数地址,对象指针类型 是通过虚函数表查找的,而多态的本质就是维护了一份虚函数表,只有对象指针才具备这样的功能。

父类指针指向子类对象 和 父类对象拷贝子类对象,存在很大的差异。前者的本质是子类对象,通过父类指针操作子类对象成员时,隐传的this指针是子类的。而父类对象拷贝子类对象,父类对象定义时进行了拷贝构造,隐传的this指针是父类的。

3. 虚函数表指针在类对象的首位
子类实例化对象时只是将虚函数表首地址存入类对象中,并没有创建表的动作,也没有子类重写虚函数后更新虚函数表的动作,所以:虚函数表是在编译期创建并更新的,运行时只是将虚函数表的地址存入类对象的首位。
反汇编查看构造函数验证标题

从内存中查看再次验证标题

4. 子类虚继承父类且父类同时存在虚函数
4.1 虚表
-
子类维护三个虚表:虚类表+虚函数表,此时会存在一个新的指针 vtordisp
-
sizeof(子类): 此时子类中除了数据成员,至少包含了3个指针,因此
sizeof(子类) = 12+sizeof(数据成员)
![image]()
4.2 虚指针排列
父类有虚函数,子类进行虚继承,子类先保存虚类表指针,再保存虚函数表指针。



浙公网安备 33010602011771号