C++:面向对象大坑:菱形继承

news2024/9/19 11:08:17

菱形继承

  • 1.单继承
    • 1.概念
  • 2.多继承
    • 2.1概念
    • 2.2菱形继承
      • 1.概念
      • 2.问题
      • 3.样例理解
        • 二义性
        • 数据冗余
        • 对于内存模型抽象化
    • 2.3菱形虚拟继承(解决菱形继承的问题)
      • 1.概念
      • 2.样例理解
          • 对于内存模型抽象化
    • 2.4总结
  • 3.问题总结
    • 1.C++有多继承,为什么?为什么Java没有?
    • 2.多继承的问题是什么?
    • 3.菱形继承的问题是什么,如何解决?
    • 4.底层角度如何解决菱形继承的问题(数据冗余和二义性)?

1.单继承

1.概念

单继承:一个子类只有一个直接父类时称这个继承关系为单继承。

图示:
在这里插入图片描述

2.多继承

2.1概念

多继承:一个子类有两个或以上直接父类时称这个继承关系为多继承。

图示:
在这里插入图片描述

2.2菱形继承

1.概念

菱形继承:菱形继承是多继承的一种特殊情况。即:一个类是另外几个类的子类,而这几个子类又是另外一个类的父类。

基本模型:

在这里插入图片描述

2.问题

但是呢,菱形继承却有一些问题:它会造成数据的冗余以及数据的二义性。比如下面,在Assistant的对象中Person成员会有两份。

在这里插入图片描述

3.样例理解

注:以下在VS2022 X64环境下验证。

class A
{
public:
	int _a;
};
class B : public A
{
public:
	int _b;
};
class C : public A
{
public:
	int _c;
};
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中的_a,编译器不知道要访问继承B的 _a还是继承C的 _a,会有歧义。

在这里插入图片描述
在这里插入图片描述

数据冗余

首先观察调试窗口:我们可以看到创建的d变量的地址。

在这里插入图片描述
然后通过内存窗口,我们可以看到d中存储了2个_a,相同的部分就会重复存储。
在这里插入图片描述

对于内存模型抽象化

在这里插入图片描述

2.3菱形虚拟继承(解决菱形继承的问题)

1.概念

菱形虚拟继承就是在菱形继承的腰部继承时(即父类第一次有多个子类时)加上关键字virtual即可。

2.样例理解

其他部分不变,我们对于上述代码进行菱形虚拟继承,并且加上一句直接访问的代码(d._a = 100),再次进行测试。

class A
{
public:
	int _a;
};
class B : virtual public A
{
public:
	int _b;
};
class C : virtual public A
{
public:
	int _c;
};
class D : public B, public C
{
public:
	int _d;
};
int main()
{
	D d;
	d.B::_a = 1;
	d.C::_a = 2;
    d._a = 100; //新增的一句代码
	d._b = 3;
	d._c = 4;
	d._d = 5;
	return 0;
}

首先观察调试窗口:我们可以看到创建的d变量的地址。
在这里插入图片描述

此时再让代码执行d.B::_a = 1这句,通过内存窗口可以看到其变化,但是和菱形继承的变化位置不同。
在这里插入图片描述
再让代码执行d.C::_a = 2这句,通过内存窗口可以看到其是直接在原来的位置处改变的,只有一份 _a。
在这里插入图片描述
再让代码执行d._a = 100这句,内存窗口变化如下:
在这里插入图片描述
再执行d._b = 3这条语句。
在这里插入图片描述
再执行d._c = 4这条语句。
在这里插入图片描述

再执行d._d = 5这条语句。
在这里插入图片描述
有个疑问,此处圈住的部分是什么呢?它看起来像一个地址(X64环境下),那么其是存储什么的呢?

解释一下,其确实为两个指针,指向的一张表。这两个指针叫虚基表指针,这两个表叫虚基表。虚基表中存的偏移量。通过偏移量可以找到下面的A。
在这里插入图片描述

通过内存窗口可以观察出:继承的B中存储了十六进制下的28,即十进制下的40。对比下图,和偏移量相等。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

对于内存模型抽象化

在这里插入图片描述

2.4总结

1.通过虚拟继承,D类对象中只有一个A类的_a,从而解决了数据冗余和二义性。
2.菱形虚拟继承的对象模型:
每个继承对象中存储一个虚基表,虚基类(即上例中的A)放在最下面,成为公共部分。
在这里插入图片描述
3.存储的地址的作用
其为虚基表指针,指向虚基表,虚基表中存储偏移量,可以找到下面存储的A。从而方便切片的场景。
4.菱形虚拟继承也会改变中间类的结构,让它们的结构和D的结构类似。
这样是为了防止以下的场景:

D d;
B b;
B& ref = d;
ref = b;

如果不存储成类似的结构,那么找到B类存储的_a就比较困难。

3.问题总结

1.C++有多继承,为什么?为什么Java没有?

这个得从C++历史发展来看,在C++发展史中,在完善面向对象的过程中,祖师爷考虑到了现实生活中确实有一部分东西可以继承多个类,比如西红柿既是水果,又是蔬菜,因此C++有了多继承。而Java在这方面通过C++的痛苦因此做出了 改变,只允许单继承。

2.多继承的问题是什么?

多继承本身没有问题,但是有多继承就会有菱形继承,而菱形继承就有许多问题。

3.菱形继承的问题是什么,如何解决?

数据冗余以及二义性。通过菱形虚拟继承解决。

4.底层角度如何解决菱形继承的问题(数据冗余和二义性)?

菱形虚拟继承在底层改变了数据的存储结构,将虚基类存储在了最下面,作为公共部分,让多继承而来的父类的数据共享,共用一份,而在继承的那部分中则存储了虚表指针,指向虚基表,从而得到其中存储的偏移量,进而可以实现切片时数据的完整性。

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

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

相关文章

react中useState的值没有改变,而是旧的数值

问题背景 想实现点击按钮就改变数据的效果,但是在控制台的打印结果,总是上一次的修改情况,并不是最新的修改后的数据 代码: import { useState, useRef } from "react";// 实现sonA的数据传递给sonB const SonA () …

史上最全的四分之一、半车再到全车7自由度常规悬架建模与仿真之一

一、悬架建模的简化过程 汽车是一个复杂的振动系统,针对不同的需求进行不同的简化。在对悬架振动分析中,把汽车车身看做一个刚体,把驾驶员座椅和驾驶员拿掉;车身以下至车轮之间的橡胶垫,连接杆,弹簧等具有…

智慧化转型赋能园区创新:科技创新引领产业智慧化,打造高效发展新格局

在全球化和信息化浪潮的推动下,园区作为区域经济发展的重要引擎,正面临着前所未有的机遇与挑战。为应对这些挑战并把握机遇,园区需积极拥抱智慧化转型,通过科技创新引领产业智慧化,打造高效发展的新格局。本文将深入探…

Unity面向切面编程

一直说面向AOP(切面)编程,好久直接专门扒出理论、代码学习过。最近因为某些原因😭还得再学学造火箭的技术。 废话不多说,啥是AOP呢?这里我就不班门弄斧了,网上资料一大堆,解释的肯定…

HTML的学习-通过创建相册WEB学习HTML-第一部分

文章目录 一、设置中文1.1、添加中文插件1.2、配置显示中文语言 二、学习开始2.1、创建项目文件夹2.2、h1标签示例:生成HTML框架示例:添加h1标签 2.3、h2标签示例:在h1标签下添加h2标签 2.4、h1标签到h6标签层次解析2.5、p标签示例&#xff1…

LORA被碾压了?多任务学习新突破,MTLoRA实现3.6倍参数高效适配

引言:多任务学习的挑战与机遇 在深度学习领域,将大规模数据集上预训练的模型适配到各种下游任务是一种常见的策略。随之而来的是参数高效微调方法的兴起,这些方法旨在将预训练模型适配到不同任务,同时只训练最少量的参数。然而&am…

力扣HOT100 - 148. 排序链表

解题思路: 归并排序 class Solution {public ListNode sortList(ListNode head) {if (head null || head.next null) return head;ListNode fast head.next, slow head;while (fast ! null && fast.next ! null) {slow slow.next;fast fast.next.nex…

基于瞬时频率的语言信号清/浊音判决和高音检测(MATLAB R2021)

语音是由气流激励声道从嘴唇或鼻孔辐射出来而产生的。根据声带是否振动,发音可分为浊音和清音。浊音和清音有明显的区别,浊音具有周期信号的特征,而清音则具有随机噪声的特征;浊音在频域上具有共振峰结构,其能量主要集…

幻方量化开源国内首个MoE大模型,全新架构、免费商用

幻方量化开源国内首个MoE大模型,全新架构、免费商用 OSC OSC开源社区 2024-01-12 19:01 广东 幻方量化旗下组织深度求索发布了国内首个开源 MoE 大模型 —— DeepSeekMoE,全新架构,免费商用。 今年 4 月,幻方量化发布公告称&…

PTA 编程题(C语言)-- 统计字符

题目标题:统计字符 题目作者:颜晖 浙大城市学院 本题要求编写程序,输入10个字符,统计其中英文字母、空格或回车、数字字符和其他字符的个数。 输入格式: 输入为…

使用YOLOv8训练自己的目标检测数据集(VOC格式/COCO格式)

yolov8训练自己的数据集 1. 下载项目2. 搭建环境3. 数据集格式转换3.1 VOC格式转YOLO格式3.2 COCO格式转YOLO格式 4. 训练数据5. 推理预测6. 模型导出 1. 下载项目 git clone https://github.com/ultralytics/ultralytics.git2. 搭建环境 conda create --name ultralytics py…

js微博发布案例

思路: 需求1:检测用户输入的字数 注册input事件 将输入文本长度赋值给对应的数值 需求2:输入不能为空 点击按钮之后判断 如果输入为空,则提示不能输入为空,并直接return 为了防止无意义的一些输入,利用字符…

NLP预训练模型-GPT-3

ChatGPT GPT-3是OpenAI开发的一个自然语言处理(NLP)预训练模型。GPT代表“生成式预训练变换器”(Generative Pretrained Transformer)。GPT-3是GPT系列的第三代模型,是一种采用了深度学习技术的强大语言模型&#xff…

C++:类与对象完结篇

hello,各位小伙伴,本篇文章跟大家一起学习《C:运算符重载》,感谢大家对我上一篇的支持,如有什么问题,还请多多指教 ! 文章目录 重新认识构造函数1.初始化列表2.explicit关键字 static成员1.sta…

通信原理(1)--信息的度量,通信系统的性能指标

通信原理(1)–信息的度量,通信系统的性能指标 1.1通信的基本概念 消息、信息与信号通信系统的组成模型数字通信的特点通信系统的分类通信的方式 1.1.1通信的发展 1.1.2消息、信息与信号 消息的定义 消息是通信系统要传输的对象,包含连续消息和离散…

车控操作系统

车控操作系统 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看…

从 Android 恢复已删除文件的 3 种简单方法

如何从 Android 恢复已删除的文件?毫不犹豫,有些人可能会认为从 Google 备份恢复 Android 文件太容易了。但是,如果删除的文件未同步到您的帐户或未备份怎么办?您错误的恢复可能会永久删除您想要的数据。因此,我们发布…

seatable部署之后network error【seatable】

这里写自定义目录标题 问题汇总 问题汇总 seatable服务部署后,组件显示正常运行,创建表单,显示Network error 点击错误信息,查看其跳转至另一个页面

数据结构----顺序表

在学习顺序表之前,我们先来了解一下数据结构。 数据是什么呢? 我们在生活中常见的名字,数字,性别等都属于数据。 结构又是什么呢? 在计算机中,结构就是用来保存数据的方式。 总的来说,数据…

【抽代复习笔记】13-群(七):变换群引理

引理:考虑等边三角形123—— 这个等边三角形的对称性可用(1),(12),(13),(23),(123),(132)表示,其中: (1)表示这个等边三角形绕着其中心点旋转360/720/.../360n,得到的图形与原图形完全重合的旋转对称变换; (12)表示这…