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

C++ 菱形继承和虚拟菱形继承

菱形继承和虚拟菱形继承

  • 菱形继承
    • 1. 概念
    • 2. 产生的问题
  • 虚拟菱形继承
    • 1.1 使用
    • 1.2 原理

菱形继承

1. 概念

菱形继承是多继承的一个特殊情况,多继承是指一个子类类继承了两个或以上的直接父类,而菱形继承问题的产生是因为该子类的父类,继承了同一个父类,注意是父类而不是直接父类。下面这张图就是直接父类,因为形状像一个菱形就称为菱形继承,但如果不是直接父类,这个形状就不是菱形了,但还是菱形继承。
在这里插入图片描述

2. 产生的问题

那菱形继承会导致什么问题呢?由图可以很容易看出,这样会导致D对象有两份A,会产生数据冗余和二义性的问题。
在这里插入图片描述
我们通过代码看看A是不是有两份

class A
{
protected:int _a;
};class B :public A
{
protected:int _b;
};class C : public A
{
protected:int _c;
};class D : public B, public C
{
protected:int _d;
};int main()
{D d;cout << sizeof(d);return 0;
}

在这里插入图片描述
再看看是不是有二义性问题

class A
{
public:int _a;
};class B :public A
{
protected:int _b;
};class C : public A
{
protected:int _c;
};class D : public B, public C
{
protected:int _d;
};int main()
{D d;cout << d._a;return 0;
}

在这里插入图片描述
下面的虚拟菱形继承可以解决这些问题。

虚拟菱形继承

1.1 使用

使用非常的简单,我们只需要在继承的时候加上virtual关键字就行了,但要注意的是virtual只需要加在会产生两份的继承位置,比如B、C都继承A,这就需要加上virtual关键字,而D继承B、C就不需要用关键字。

class A
{
public:int _a = 1;
};class B :virtual public A
{
protected:int _b = 2;
};class C :virtual public A
{
protected:int _c = 3;
};class D : public B, public C
{
protected:int _d = 4;
};int main()
{D d;cout << d._a;return 0;
}

在这里插入图片描述

1.2 原理

我们可以通过成员对象模型来研究原理。
我们通过内存窗口先来看一下没有虚拟继承的菱形继承对象模型
在这里插入图片描述
很明显的可以看到A有两份,造成了数据冗余和二义性,我们在来看一下虚拟继承以后的对象模型。
在这里插入图片描述
可以看到A只有一份,成功的解决了问题,但又产生了一个新问题,A不在B和C里,那B和C如何找到A呢?看上面的模型,细心的同学会发现B和C多了一个东西,那个东西就是解决这个问题的关键,叫做虚基表指针,指向的是一个虚基表,表里面存放的是偏移量,通过这个偏移量找到A

相关文章:

  • C++引用详解
  • 在WebSocket中使用Redis出现空指针异常解决方案
  • Linux——如何使用sftp命令轻松上传和下载文件
  • HTTPS实现原理
  • 软件工程知识梳理2-需求分析
  • 离线使用Element UI和Vue
  • Spring Cloud Gateway
  • linux☞ Centos 基础篇
  • 【C++】构造函数和析构函数详解
  • python查询xml类别
  • 在JAVA中如何使用ASCLL码
  • go语言文件操作
  • 回归预测 | Matlab实现CPO-LSSVM冠豪猪算法优化最小二乘支持向量机多变量回归预测
  • JVM 执行引擎
  • Linux实验记录:使用iptables
  • [js高手之路]搞清楚面向对象,必须要理解对象在创建过程中的内存表示
  • 【跃迁之路】【669天】程序员高效学习方法论探索系列(实验阶段426-2018.12.13)...
  • Android Volley源码解析
  • Android路由框架AnnoRouter:使用Java接口来定义路由跳转
  • ES6核心特性
  • ES6简单总结(搭配简单的讲解和小案例)
  • HashMap ConcurrentHashMap
  • JavaWeb(学习笔记二)
  • Java多态
  • js操作时间(持续更新)
  • Redis 中的布隆过滤器
  • 蓝海存储开关机注意事项总结
  • 排序算法之--选择排序
  • 深入 Nginx 之配置篇
  • 吐槽Javascript系列二:数组中的splice和slice方法
  • 这几个编码小技巧将令你 PHP 代码更加简洁
  • 阿里云移动端播放器高级功能介绍
  • #我与Java虚拟机的故事#连载05:Java虚拟机的修炼之道
  • $refs 、$nextTic、动态组件、name的使用
  • (16)Reactor的测试——响应式Spring的道法术器
  • (DFS + 剪枝)【洛谷P1731】 [NOI1999] 生日蛋糕
  • (env: Windows,mp,1.06.2308310; lib: 3.2.4) uniapp微信小程序
  • (分享)自己整理的一些简单awk实用语句
  • (附源码)springboot社区居家养老互助服务管理平台 毕业设计 062027
  • (附源码)ssm智慧社区管理系统 毕业设计 101635
  • (免费领源码)Java#Springboot#mysql农产品销售管理系统47627-计算机毕业设计项目选题推荐
  • (四)库存超卖案例实战——优化redis分布式锁
  • **python多态
  • .Net Core webapi RestFul 统一接口数据返回格式
  • .NET Framework 4.6.2改进了WPF和安全性
  • .NET 命令行参数包含应用程序路径吗?
  • @configuration注解_2w字长文给你讲透了配置类为什么要添加 @Configuration注解
  • [ C++ ] template 模板进阶 (特化,分离编译)
  • [1]-基于图搜索的路径规划基础
  • [Android]How to use FFmpeg to decode Android f...
  • [C++]类和对象【上篇】
  • [CTO札记]如何测试用户接受度?
  • [github全教程]github版本控制最全教学------- 大厂找工作面试必备!
  • [Java算法分析与设计]--线性结构与顺序表(List)的实现应用
  • [MySQL] 二进制文件