当前位置: 首页 > news >正文

菱形虚拟继承的原理

一 :菱形继承的问题

 

普通的菱形继承存在数据冗余和二义性的问题 ,如下代码:

class Person {
public:
	string _name; //姓名
};
 
class Student : public Person {
protected:
	int _num; //学号
};
 
class Teacher : public Person {
protected:
	int _id; //编号
};
 
class Assistant : public Student, public Teacher {
protected:
	string _majorCourse; //主修课程
};
 
void Test() {
	
	Assistant a;
	a._name = "peter";//这样会有二义性无法明确知道访问的是哪一个

 
	// 需要显示指定访问哪个父类的成员可以解决二义性问题,但是数据冗余问题无法解决
	a.Student::_name = "xxx";
	a.Teacher::_name = "yyy";
}

解释:

显示地指定访问哪个父类的成员可以解决二义性问题,但是数据冗余问题无法解决 ,所以有了虚拟菱形继承

二:虚拟菱形继承

class Person {
public:
	string _name;
	int _hugeArr[10000];
};
 
// 虚继承
class Student : virtual public Person {
protected:
	int _num;
};
 
// 虚继承
class Teacher : virtual public Person {
protected:
	int _id;
};
 
class Assistant : public Student, public Teacher {
protected:
	string _majorCourse;
};

在类腰部位置加一个 virtual 关键字

虚拟继承不但解决数据冗余,还解决了二义性

为何请看三~

三:虚拟菱形继承的原理

 

为了研究虚拟继承原理,我们给出了一个简化的菱形继承继承体系,再借助 内存窗口观察对象成
员的模型。

1:非虚拟菱形继承的内存分布

//类A
class A
{
public:
  int _a;
};


//B虚拟继承A
class B :  public A
{
public:
  int _b;
};


//C虚拟继承A
class C :  public A
{
public:
  int _c;
};


//D再继承B和A
class D : public B, public C
{
public:
  int _d;
};



int main()
{
 D d;

//对成员变量的赋值
 d.B::_a = 1;
 d.C::_a = 2;
 d._b = 3;
 d._c = 4;
 d._d = 5;

 return 0;
}

借助内存窗口观察:

可以发现:

①:d这个对象中存放了所有的变量,无论是继承和还是自己的

②:1和3紧挨因为类B中是这两个成员变量,2和4紧挨着因为类C中是这两个成员变量

③:d的成员变量放在最后

2:虚拟菱形继承的内存分布

//类A
class A
{
public:
  int _a;
};


//B虚拟继承A
class B : virtual public A
{
public:
  int _b;
};


//C虚拟继承A
class C : virtual public A
{
public:
  int _c;
};


//D再继承B和A
class D : public B, public C
{
public:
  int _d;
};



int main()
{
 D d;

//对成员变量的赋值
 d.B::_a = 1;
 d.C::_a = 2;
 d._b = 3;
 d._c = 4;
 d._d = 5;

 return 0;
}

借助内存窗口观察:

解释:_a不再存在两份,变成只有一份

Q:类B和类C中的第一行存放的地址有什么意义?

A:解释如图

总结:虚继承中,B和C类中,并没有直接存放类A,类A被存放在了一个公共的位置,在类B和C中,额外存放了一个地址,该地址指向的地方为虚基表,各自的虚基表中能得到各自的类和类A的相隔字节数

Q:为什么这么的麻烦?不直接把相隔的字节数直接存放在类B和类C中?却要存放一个地址,改地址指向的虚基表中才有相隔的字节数

A:因为虚基表中不止仅仅有相隔字节数这一信息,很多信息暂时还没到学的时候,而类B和类C中只有4字节的位置,所以存在虚基表的地址刚刚好

一个需要虚基表的场景:

B* pb = &d;//d是一个已有类D的对象
pb->_a++;

解释:在代码中的切片赋值的时候,我们只保留了类B的部分,此时我们要在pb中找到A的成员变量,通过类B中的虚基表即可

 

相关文章:

  • WPF 浅述ToolTipService.ShowOnDisabled
  • Flask接口开发--GET接口
  • 路由选型终极对决:直连/静态/动态三大类型+华为华三思科配置差异,一张表彻底讲透!
  • Java Collection API增强功能系列之一 Arrays.asList()
  • 如何分析和解决服务器的僵尸进程问题
  • nginx服务配置练习
  • [蓝桥杯 2023 省 A] 异或和之和
  • P5356 [Ynoi Easy Round 2017] 由乃打扑克 Solution
  • Redis分布式寻址算法
  • XXL-Job 二次分片是怎么做的?有什么问题?怎么去优化的?
  • ARCGIS PRO SDK ProWindow自定义窗口DataGrid控件的应用
  • langchain-ollama的ragflow简单实现
  • 车载以太网网络测试 -23【TCPUDP通信示例】
  • 模糊规则激活方法详解(python实例对比)
  • 【Tauri2】001——安装及运行
  • shadcn如何给dialog增加关闭按钮和隐藏右上角关闭按钮
  • 重写ring3 API函数
  • 安宝特应用 | 军工级数据安全赋能保密产品数字化交付
  • 第五章 动态规划
  • Linux文件描述符及重定向
  • 美英达成贸易协议,美股集体收涨
  • 习近平出席俄罗斯总统举行的欢迎仪式
  • 高进华“控股”后首份年报出炉,史丹利账上可动资金大幅缩水
  • 4月外汇储备增加410亿美元,黄金储备连续6个月增加
  • 李云泽:房地产“白名单”贷款审批通过金额增至6.7万亿元
  • 董卓的前半生:边荒之地的工具人