C++菱形继承以及解决方法--虚继承 虚基表

news2024/9/21 19:08:39

目录

    • 菱形继承形成原因
      • 出现二义性变量的内存布局
    • 应对方案
      • 虚继承 vitrual
      • 解决二义性变量内存布局--虚基表
    • 感悟
    • 关于代码复用等的另一种关系-组合

菱形继承形成原因

多继承,呈菱形状
在这里插入图片描述

菱形继承代码:

class A 
{
public:
    A() {}
    int _a ;
};
class B :public A 
{
public:
    //会存在父的int a;
    B() {}
    int _b ;
};
class C :public A 
{
public:
   //会存在父的int a;
    C() {}
    int _c ;
};
class D :public B,public C 
   
{
public:
   //会存在父的int a;    问题来了这个a是  父亲b中的a 还是 父亲c中的a -- 二义性;
    
   //父的int b;
   //父的int c;
    D() {}
    int _d ;
};
int main()
{
    
   
    D d;
    d.B::_a = 1;
    d.C::_a = 2;
    d._b = 3;
    d._c = 4;
    b._d = 5;
    cout << d._a << endl;//报错  提示b.a具有二义性
    return 0;

}

出现二义性变量的内存布局

在这里插入图片描述

可以看到上图中紫色框两部分,是出现二义性的两份A::_a变量,编译器无法自主确定需要用哪一个,可以d::A_a 或者 d::B_a这样使用;

应对方案

虚继承 vitrual

vitrual修饰使派生类出现二义性的父类继承部分(菱形的腰部)

class A 
{
public:
    A() {}
    int _a ;
};
class B :virtual public A //virtual修饰
{
public:
    //父的int a;
    B() {}
    int _b;
};
class C :virtual public A  //virtual修饰
{
public:
   //父的int a;
    C() {}
    int _c ;
};
class D :public B,public C 
   
{
public:

    //自己的 int a;(二义性的父亲继承经virtual修饰)
   //父的int b;
   //父的int c;
    D() {}
    int _d;
};
int main()
{
    
    D d;
    d.B::_a = 1;
    d.C::_a = 2;
    d._b = 3;
    d._c = 4;
    b._d = 5;
    cout << d._a << endl;//没问题,输出2,这个2是D类成员通过继承,使得d自己独有且只有一份的 A::_a成员变量;
    return 0;
}

解决二义性变量内存布局–虚基表

在这里插入图片描述

可以看到原先存放两个二义性数据A::a和B::a的位置,变成了一个地址?

这个两个地址就叫虚基表指针

通过对虚基表的进一步内存研究,发现了虚基表紧着得下一个位置存放了一个偏移量,这个偏移量是存放该虚基表指针的内存位置,与当前派生类独有一份的成员变量_a之间的偏移长度;

这样我们直接使用d::a的时候,因为独有一份,也不会出现数据二义性的问题了;

注意,这和多态中的虚表(虚函数表两回事)

其次,虚基表的指针,经过测试,也是某个多继承派生类的多对象共用的;

eg: D d1,d2; 其中d1,d2两个对象 上图的这两张虚基表指针是一样的,原因很简单,D类类型都一样,那么某个位置起,到另一个相对位置偏移量肯定是固定的!

(同类型的虚表指针也如此,复用节省空间嘛)

感悟

继承,多态无疑为我们创造了很多的价值,但是像菱形继承这种弊端也是存在的,本质是多继承而引起的问题,在一些语言禁止了多继承的行为,总之有利有弊,虽然C++允许了多继承,但还是尽量别写多继承这种模式,复杂度和出现问题的概率都很大;

关于代码复用等的另一种关系-组合

继承是每个派生类都能相对于继承is-a的关系; 每个派生类对象都是一个基类对象; 耦合度高

在这里插入图片描述

优先考虑组合has-a的关系; eg: 汽车-轮胎,has-a,组合(class 轮胎 作为class 车的成员嵌套) 耦合度低

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/177453.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

NAT技术原理、使用场景

随着Internet的发展和网络应用的增多&#xff0c;有限的IPv4公有地址已经成为制约网络发展的瓶颈。为解决这个问题&#xff0c;NAT&#xff08;Network Address Translation&#xff0c;网络地址转换&#xff09;技术应需而生。 NAT技术主要用于实现内部网络的主机访问外部网络…

JDK8 新特性之新增的Optional类

目录 一&#xff1a;以前对null的处理方式 二&#xff1a;Optional类介绍 三&#xff1a;Optional的基本使用 Optional的高级使用 小结 一&#xff1a;以前对null的处理方式 Test public void test01() { String userName "凤姐"; // String userName null; …

十八、Gtk4-Stateful action

有些动作action有状态。状态的典型值是布尔值或字符串。但是&#xff0c;如果你愿意&#xff0c;也可以使用其他类型的状态。 具有状态的动作称为有状态的。 Stateful action without a paramete 有些菜单被称为切换菜单。例如&#xff0c;全屏菜单有一个状态&#xff0c;它…

在甲骨文云容器实例(Container Instances)上部署edge

甲骨文云推出了容器实例&#xff0c;这是一项无服务器计算服务&#xff0c;可以即时运行容器&#xff0c;而无需管理任何服务器。 今天我们尝试一下通过容器实例部署edge。 Step1. 创建容器实例 在甲骨文容器实例页面&#xff0c;单击"创建容器实例"&#xff0c; …

审批工作流—ccflow

审批工作流—ccflow目录概述需求&#xff1a;设计思路实现思路分析1.java 代码分析参考资料和推荐阅读Survive by day and develop by night. talk for import biz , show your perfect code,full busy&#xff0c;skip hardness,make a better result,wait for change,challen…

LeetCode[547]省份数量

难度&#xff1a;中等题目&#xff1a;有 n个城市&#xff0c;其中一些彼此相连&#xff0c;另一些没有相连。如果城市 a与城市 b直接相连&#xff0c;且城市 b与城市 c直接相连&#xff0c;那么城市 a与城市 c间接相连。省份 是一组直接或间接相连的城市&#xff0c;组内不含其…

Leetcode:93. 复原 IP 地址(C++)

目录 问题描述&#xff1a; 实现代码与解析&#xff1a; 回溯&#xff1a; 原理思路&#xff1a; 问题描述&#xff1a; 有效 IP 地址 正好由四个整数&#xff08;每个整数位于 0 到 255 之间组成&#xff0c;且不能含有前导 0&#xff09;&#xff0c;整数之间用 . 分隔。…

leetcode刷题记录总结-2.链表

文章目录一、重排列表[1. 奇偶链表](https://leetcode.cn/problems/odd-even-linked-list/solutions/)题解二、链表的增、删、改、查[203. 移除链表元素](https://leetcode.cn/problems/remove-linked-list-elements/)题解不简洁代码简洁代码707.设计链表题解不简洁代码优化后的…

mysql主从复制配置(windows和linux操作都有)

我是目录主从复制是什么&#xff1f;操作实践验证主从设置主从复制是什么&#xff1f; mysql主从复制是一个异步的复制过程&#xff0c;底层是基于mysql数据库自带的二进制日志功能。就是一台或多台mysal数据库&#xff08;slave&#xff0c;即从库&#xff09;从另一台mysql数…

macOS Big Sur 11.7.3 (20G1116) 正式版 ISO、PKG、DMG、IPSW 下载

本站提供的 macOS Big Sur 软件包&#xff0c;既可以拖拽到 Applications&#xff08;应用程序&#xff09;下直接安装&#xff0c;也可以制作启动 U 盘安装&#xff0c;或者在虚拟机中启动安装。 请访问原文链接&#xff1a;https://sysin.org/blog/macOS-Big-Sur/&#xff0…

【Python百日进阶-Web开发-Linux】Day236 - Win11安装Windows Subsystem for Android(WSA)

文章目录一、Win11运行安卓app前提条件二、Win11运行安卓app支持以下新特性三、Win11运行安卓app操作步骤3.1 修改定位3.2 开启VT虚拟化3.3 开启电脑的Hyper-V和虚拟机平台四、WSA下载4.1 百度网盘下载4.2 store.rg-adguard.net下载五、WSA安装&#xff08;没有成功&#xff0c…

C++初阶--继承

目录 继承的概念 继承定义 继承基类成员访问方式 基类和派生类对象的赋值转换 继承中的作用域 派生类的默认成员函数 友元关系不能继承 基类static成员 菱形继承与菱形虚拟继承 虚拟继承解决数据冗余和二义性的原理 继承和组合 继承的概念 继承是类层次的复用。 继…

Golang 泛型学习

Golang 泛型 今天来学习下Golang中泛型的基础知识。使用泛型&#xff0c;开发者可以声明一个函数来适应不同类型的参数&#xff0c;避免由于参数类型不一致而声明多个处理逻辑类似的函数。在本教程中&#xff0c;将声明两个简单的非泛型函数&#xff0c;然后在单个泛型函数中实…

这些实体店直播必备技巧,新手直接套用就能火!

随着直播的受众越来越广、门槛越来越低&#xff0c;入局服装直播的实体店越来越多。对于服装厂商来说&#xff0c;服装产业链越靠下游毛利率越高&#xff0c;品牌商和销售商利润远高于加工生产商&#xff0c;约在40-50%&#xff0c;而服装制造商的毛利率仅在15%左右。而对于本土…

JDK8 新特性之收集Stream流中的结果

目录 一&#xff1a;Stream流中的结果到集合中 二&#xff1a;Stream流中的结果到数组中 三&#xff1a;对流中数据进行聚合计算 四&#xff1a;对流中数据进行分组 五&#xff1a;对流中数据进行多级分组 六&#xff1a;对流中数据进行分区 七&#xff1a;对流中数据进行拼接…

8.Java循环高级综合练习-无限循环和跳转控制语句,逢七过,平方根,判断是否为质数,猜数字小游戏

文章目录前言一、无限循环1.这三种循环中哪一种无限循环是最常用的呢?2.注意事项:二、跳转控制语句三、逢七过四、平方根五、判断该整数是否为一个质数六、猜数字小游戏保底机制总结前言 一、无限循环 1.这三种循环中哪一种无限循环是最常用的呢? 当然是右上角的while循环啦…

【若依】若依字典管理页面中列表按钮功能的实现

0. 功能实现描述 1. 代码实现 ScStfController.java /*** 查询员工证书* param stfId* param modelMap* return*/ RequiresPermissions("sc:stf:cert") GetMapping("/cert/{stfId}") public String detail(PathVariable("stfId") Long stfId, …

结构型模式-组合模式

1.概述 对于这个图片肯定会非常熟悉&#xff0c;上图我们可以看做是一个文件系统&#xff0c;对于这样的结构我们称之为树形结构。在树形结构中可以通过调用某个方法来遍历整个树&#xff0c;当我们找到某个叶子节点后&#xff0c;就可以对叶子节点进行相关的操作。可以将这颗树…

谷粒学院——Day19【项目部署】

❤ 作者主页&#xff1a;欢迎来到我的技术博客&#x1f60e; ❀ 个人介绍&#xff1a;大家好&#xff0c;本人热衷于Java后端开发&#xff0c;欢迎来交流学习哦&#xff01;(&#xffe3;▽&#xffe3;)~* &#x1f34a; 如果文章对您有帮助&#xff0c;记得关注、点赞、收藏、…

Java中的hashCode,真的很容易弄懂

写这篇文章是因为在看hashMap源码时遇到有什么hashcode值&#xff0c;然后就去查&#xff0c;脑袋里面是有印象的&#xff0c;不就是在Object中有equals和hashcode方法嘛&#xff0c;这在学java基础的时候就遇到过&#xff0c;不过那时候无所谓&#xff0c;囫囵吞枣&#xff0c…