虚函数浅析

0. 原理简述

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

1. 多个对象指向同一个虚函数表

image

2. 普通对象和指针对象调用虚函数

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

image

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

image

3. 虚函数表指针在类对象的首位

子类实例化对象时只是将虚函数表首地址存入类对象中,并没有创建表的动作,也没有子类重写虚函数后更新虚函数表的动作,所以:虚函数表是在编译期创建并更新的,运行时只是将虚函数表的地址存入类对象的首位

反汇编查看构造函数验证标题

image

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

image

4. 子类虚继承父类且父类同时存在虚函数

4.1 虚表

  • 子类维护三个虚表:虚类表+虚函数表,此时会存在一个新的指针 vtordisp

  • sizeof(子类): 此时子类中除了数据成员,至少包含了3个指针,因此 sizeof(子类) = 12+sizeof(数据成员)
    image

4.2 虚指针排列

父类有虚函数,子类进行虚继承,子类先保存虚类表指针,再保存虚函数表指针。

image

posted @ 2023-04-14 21:42  Qing-Huan  阅读(91)  评论(0)    收藏  举报