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

C++:菱形继承与虚继承

看下面这个示例代码

class A{
public:
int num=10;
A(){cout<<"A构造"<<endl;}
virtual void fun(){cout<<"A虚函数"<<endl;}
};

class B:public A{
public:
B(){cout<<"B构造"<<endl;}
void fun(){cout<<"B虚函数"<<endl;}
};

class C:public A{
public:
C(){cout<<"C构造"<<endl;}
void fun(){cout<<"C虚函数"<<endl;}
};

class D:public C,public B{
public:
D(){cout<<"D构造"<<endl;}
void fun(){cout<<"D虚函数"<<num<<endl;}
};

这段代码你会发现这段代码编译不通过,因为D类的虚函数在访问num时不知道访问哪个,将这个虚函数里面的内容清空然后执行会得到以下结果:
在这里插入图片描述

可以看到D多次继承了同一个基类,这样就造成了构造D时构造了多个A,问题本身没有什么影响但是如果D需要访问A中的东西时就会有两个渠道,通过B或者C,这时候加上作用域的话就可以运行了,但是这样太麻烦了,而且对共同的基类A真的没必要构造两次,为了处理这种情况引入了虚继承的概念。
之前介绍过虚函数,虚继承和它类似

  • 发生虚继承的时候就会产生一个虚基表和相应的虚基表指针
  • 虚基表是静态的,这点和虚函数表差不多
  • 发生虚继承后对任意类只会创建一次
  • 虚基表存储虚基表指针到其基类的偏移量
  • 一个类只会有一个虚基表,但是可以有多个虚基表指针

这些概念后面梳理,现在先看修改后的代码

class A{
public:
int num=10;
A(){cout<<"A构造"<<endl;}
virtual void fun(){cout<<"A虚函数"<<endl;}
};
class B:virtual public A{
public:
B(){cout<<"B构造"<<endl;}
void fun(){cout<<"B虚函数"<<endl;}
};
class C:virtual public A{
public:
C(){cout<<"C构造"<<endl;}
void fun(){cout<<"C虚函数"<<endl;}
};
class D:virtual public C,virtual public B{
public:
D(){cout<<"D构造"<<endl;}
void fun(){cout<<"D虚函数"<<num<<endl;}
};

看看执行结果
在这里插入图片描述
可以看出问题被解决了,接下来看它在内存中的分布
在vs开发者命令行模式下输入下面的指令即可

cl /d1 reportSingleClassLayoutXXX 文件名.cpp

xxx替换为自己的类名,我这里是D

在这里插入图片描述
可以看到类的结构还是很清晰的,每个使用虚继承的类头部都有一个虚基表指针,同时虚函数表指针不再出现在头部,不需要过多解释自己看吧
在这里插入图片描述
虚继承通过减少基类的重复创建解决了多次继承同一基类造成的二义性问题,借助虚基表完成了基类的定位,可以说很是牛皮,但是缺点也很明显它破坏了类中的原有布局,它使类中的内存分布情况程序多样化,现在虚函数表指针可能有多个甚至位置也会按照继承的顺序而改变,内存的分布依赖于代码书写,所以说要慎用,虽然我们不需要过多关注内存,但是对性能的影响却是真实存在的。


http://www.kler.cn/a/271783.html

相关文章:

  • iperf 测 TCP 和 UDP 网络吞吐量
  • 计算机毕业设计Python+CNN卷积神经网络高考推荐系统 高考分数线预测 高考爬虫 协同过滤推荐算法 Vue.js Django Hadoop 大数据毕设
  • 【MySQL】悲观锁和乐观锁的原理和应用场景
  • 多协议网关BL110钡铼6路RS485转MQTT协议云网关
  • Acwing94递归实现排列型枚举
  • 【redis】redis操作set类型的key发生了什么?
  • 数据分析 | NumPy
  • 爬虫的基本原理介绍,实现以及问题解决
  • Linux——线程池
  • C/C++整数和浮点数在内存中存储
  • Linux学习(4)——使用编辑器
  • 第十三届蓝桥杯省赛C++ C组《全题目+题解》
  • Xlua - 集成rapidjson(json序列化)
  • 力扣111---二叉树的最小深度(简单题,Java,递归+非递归)
  • 用户数据的FLASH存储与应用(FPGA架构)
  • matlab去除图片上的噪声
  • SpringBoot整合异步任务
  • unity3d Animal Controller的Animal组件中Stances,Advanced基础部分理解
  • 【Jenkins】data stream error|Error cloning remote repo ‘origin‘ 错误解决【亲测有效】
  • 2k_Day3:搞清楚最基本简单的crud
  • 大模型笔记:吴恩达 ChatGPT Prompt Engineering for Developers(1) prompt的基本原则和策略
  • 论文阅读——RemoteCLIP
  • Axios:贯穿前后端的数据链
  • D-Star 寻路算法
  • 【LGR-179-Div.2】复旦勰码 3 月月赛 II ZHYOI Round 4(A~B)
  • [MySQL]数据库基础