C++普通继承、多继承、虚继承内存空间排布分析
一、普通继承
- 代码
class A { public: virtual void virtualfunA(){ } virtual void virtualfunAA(){ } void funA(){ } public: int a; }; class B : public A { public: virtual void virtualfunA(){ } virtual void virtualfunB(){ } void funB(){ } public: int b; }; int main(){ A obj1; B obj2; return 0; }
- 内存结构
看到我发现了一个有趣的地方,就是B类中的虚函数virtualfunB出现在obj2的虚表中。
- 总结 普通继承中,子类重写父类的虚函数后会在虚表中覆盖父类的虚函数,子类增加特有的虚函数, 要在第一个虚表中添加.
二、多继承
- 代码
class A1 { public: virtual void funA1(){ } virtual void funA11(){ } public: int a1; }; class A2 { public: virtual void funA2(){ } virtual void funA22(){ } public: int a2; }; class B : public A1 ,public A2 { public: virtual void funA1(){ } virtual void funA2(){ } virtual void funB(){ } public: int b; }; int main() { B obj; return 0; }
- 内存结构
总结:多继承的内存空间顺序是按照继承顺序排布的。
三、菱形继承
描述:上面的多继承中有一个经典的菱形继承问题,如果多继承的对象中存在某两个类继承同一个基类,那么会出现数据冗余现象,这会导致数据不一致。
如图: 这种情况C对象中会出现两个a变量
- 代码
#include<iostream> using namespace std; class A { public: int a; }; class B1 : public A { public: int b1; }; class B2 : public A { public: int b2; }; class C : public B1,public B2 { public: int c; }; int main() { C obj; return 0; }
- 内存结构 总结:这种情况我么可以用虚继承来解决这类问题
四、虚继承
虚继承特性: 父类和子类在空间上倒置关系(与普通继承比较) 虚继承, 子类会复制父类的虚表, 此外, 自己特有虚函数, 自己会有虚表, 自己也会有对应的虚指针. 2个虚指针, 一个指向父类复制过来的虚表,一个指向自己的虚表 子类存在指向虚基类(虚继承里面的基类) 的虚基表 , 子类会有指向虚基表的指针 vbptr , 虚基表里面内容是指向自己和虚基类的偏移量 最底层的子类, 完成虚基类的构造.
1.部分虚继承
- 代码
class A { public: virtual void funA(){ } public: int a; }; class B1 : virtual public A { public: virtual void funB1(){ } public: int b1; }; class B2 : virtual public A { public: virtual void funB2(){ } public: int b2; }; class C : public B1,public B2 { public: virtual void funC(){ } public: int c; }; int main() { C obj; return 0; }
2.内存结构 vbptr的作用是找到自己的虚表和自己继承类的虚表
2.完全虚继承
- 代码
class A { public: virtual void funA(){ } public: int a; }; class B1 : virtual public A { public: virtual void funB1(){ } public: int b1; }; class B2 : virtual public A { public: virtual void funB2(){ } public: int b2; }; class C : virtual public B1,public B2 { public: virtual void funC(){ } public: int c; }; int main() { C obj; return 0; }
- 内存结构 vbptr的作用是找到自己的虚表和自己继承类的虚表
总结
由内存结构可知,这两种方法都是可以解决菱形继承问题的。