基类与派生类是否共用虚函数表?当时印象中不是,最后左右摇摆中说了我不是很确定。其实提到虚函数表,会想到虚函数表指针,然后想到虚基类表指针,然后就又混淆了

虚函数表

  1. 对于基类,如果有虚函数,那么先存放虚函数表指针,然后存放自己的数据成员;如果没有虚函数,那么直接存放数据成员。
  2. 对于单继承的类对象,先存放父类的数据拷贝(包括虚函数表指针),然后是本类的数据(本类有自己的虚函数就添加到拷贝过来的虚函数表的后面)。
  3. 如果重写了父类的某些虚函数,那么新的虚函数将虚函数表中父类的这些虚函数覆盖
  4. 对于多重继承,先存放第一个父类的数据拷贝,在存放第二个父类的数据拷贝,一次类推,最后存放自己的数据成员。其中每一个父类拷贝都包含一个虚函数表指针。如果子类重写了某个父类的某个虚函数,那么将该父类虚函数表的函数覆盖。另外,子类自己的虚函数,存储于第一个父类的虚函数表后边部分。
  5. 当对象的虚函数被调用时,编译器去查询对象的虚函数表,找到该函数,然后调用

    虚基类表

  • 如果是虚继承的类对象,那么先存放虚基类表指针,然后存放自己的数据成员,如果同时还有虚函数,则先存放虚函数表指针,再存放虚基类表指针,最后存放自己的数据成员
  • 虚基类表第一项为当前子对象相对于虚基类表指针的偏移,第二项为继承的虚基类数据相对于虚基类表指针的偏移参考:
    https://blog.csdn.net/fenxinzi557/article/details/51995911

https://blog.csdn.net/qq_41689072/article/details/81350984
https://blog.csdn.net/primeprime/article/details/80776625
https://blog.csdn.net/shanghx_123/article/details/82973791

1.B2对象的前4个字节存放的是虚表的地址,其后才是B2该对象的成员变量;(虚函数表我们也叫做虚表)。
2.若B2这个类中有多个虚函数,那么其对象大小还是8,因为前4个字节是存放虚函数表的地址,在这个虚函数表(函数指针数组)里面每个元素才是每个虚函数的地址。
image.png
单继承:
1.先将基类中的虚表内容拷贝一份到派生类虚表中
2.如果派生类重写了基类中某个虚函数,用派生类自己的虚函数替换虚表中基类的虚函数
3.派生类自己新增加的虚函数按其在派生类中的声明次序增加到派生类虚表的最后
多继承:
4.最后一句:子类继承了多少个父类,就有多少个虚函数表,也就是有多个虚函数表指针(每个4字节),子类内的虚函数放在第一个虚函数表中

子类的内存分布:

子类的内存分布 父类的虚函数表指针
同时也是子类虚函数表的指针
父类的数据成员
子类的数据成员