大佬写的https://blog.csdn.net/caoshangpa/article/details/80112673
同类对象共用虚函数表
(对象中不含虚函数表,只有一个指向虚函数表的指针)
重写后子类虚函数表(有重写,没有新的虚函数)
重写后子类虚函数表 (没有有重写,有新的虚函数)
多重继承后子类虚函数表
上图分析:
派生类重写:
virtual void base1_fun1() {}
virtual void base2_fun2() {}
基类虚函数表被重写;
对于派生类自己的虚函数
virtual void derive1_fun1() {}
virtual void derive1_fun2() {}
派生类虚函数表位置:保存到第1个拥有虚函数表的那个基类的后面的。
谁有虚函数表, 谁就放在前面!
当base1没有虚函数时:
保存到第1个拥有虚函数表的那个基类的后面的。谁有虚函数表, 谁就放在前面!还是正确的
两个基类都没有虚函数表
现在__vfptr已经独立出来了, 不再属于Base1和Base2!
总结:
由于继承完全拥有父类的所有, 包括数据成员与虚函数表, 所以:把一个继承类强制转换为一个基类是完全可行的。
子类的重写或虚函数 会影响 复制来的父类虚函数表。
永远不会影响 父类本身的虚函数表。
如果有一个Derive1的指针, 那么:
得到Base1的指针: Base1* pb1 = pd1;
得到Base2的指针: Base2* pb2 = pd1;
得到Base3的指针: Base3* pb3 = pd1;
非常值得注意的是:
这是在基类与继承类之间的转换, 这种转换会自动计算偏移! 按照前面的布局方式!
也就是说: 在这里极有可能: pb1 != pb2 != pb3 ~~, 不要以为她们都等于 pd1!
函数调用
如果不是虚函数, 直接调用指针对应的基本类的那个函数
如果是虚函数, 则查找虚函数表. //查的是子类的虚函数表 运行时多态实现原理
为什么父类析构函数要用虚函数:
fa* fa1 = son1;
//相当于son强转fa,因为fa有的son1都有,所以可以执行
//然后把son把fa覆盖的部分,覆盖到fa1下 就算完成了。
默认的析构函数执行的是fa();
构造时执行fa();
析构时:析构为虚函数,执行~son(),把 ~fa()覆盖;
析构为普通函数,执行~fa();