C++普通继承、多继承、虚继承内存空间排布分析

一、普通继承

  1. 代码
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;
}
  1. 内存结构
看到我发现了一个有趣的地方,就是B类中的虚函数virtualfunB出现在obj2的虚表中。
  1. 总结 普通继承中,子类重写父类的虚函数后会在虚表中覆盖父类的虚函数,子类增加特有的虚函数, 要在第一个虚表中添加.

二、多继承

  1. 代码
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;
}
  1. 内存结构

总结:多继承的内存空间顺序是按照继承顺序排布的。

三、菱形继承

描述:上面的多继承中有一个经典的菱形继承问题,如果多继承的对象中存在某两个类继承同一个基类,那么会出现数据冗余现象,这会导致数据不一致。

如图: 这种情况C对象中会出现两个a变量

  1. 代码
#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;
}
  1. 内存结构 总结:这种情况我么可以用虚继承来解决这类问题

四、虚继承

虚继承特性: 父类和子类在空间上倒置关系(与普通继承比较) 虚继承, 子类会复制父类的虚表, 此外, 自己特有虚函数, 自己会有虚表, 自己也会有对应的虚指针. 2个虚指针, 一个指向父类复制过来的虚表,一个指向自己的虚表 子类存在指向虚基类(虚继承里面的基类) 的虚基表 , 子类会有指向虚基表的指针 vbptr , 虚基表里面内容是指向自己和虚基类的偏移量 最底层的子类, 完成虚基类的构造.

1.部分虚继承

  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.完全虚继承

  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 : virtual public B1,public B2
{
          
   
public:
	virtual void funC(){
          
   }
public:
	int c;
};

int main()
{
          
   
	C obj;
	return 0;
}
  1. 内存结构 vbptr的作用是找到自己的虚表和自己继承类的虚表

总结

由内存结构可知,这两种方法都是可以解决菱形继承问题的。

经验分享 程序员 微信小程序 职场和发展