利用虚继承解决菱形继承(钻石继承)的问题 学习笔记

2023-12-20 05:28

本文主要是介绍利用虚继承解决菱形继承(钻石继承)的问题 学习笔记,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

菱形继承概念:

两个派生类继承同一个基类

又有某个类同时继承两个派生类

这种继承又被称为菱形继承,或者钻石继承

定义一个基类Animal,两个派生类Sheep、Camal,SheepCame继承于两个派生类

class Animal
{
public:int m_Age;
};
class Sheep :  public Animal { };
class Camel :  public Animal { };
class SheepCamel : public Sheep, public Camel { };

void test()
{
    SheepCamel S;
    S.m_Age = 20;//报错,"SheepCamel::m_Age不明确"
}

问题(1):

当创建SheepCamel类对象,直接初始化m_Age时,会出现二义性,即不知是继承于Sheep父类还是Camel父类

若想初始化m_Age,则需要加作用域来强调继承于哪个父类

void test()
{
    SheepCamel S;
    S.Sheep::m_Age = 10;
    S.Camel::m_Age = 20;
    cout << S.Sheep::m_Age << endl; // 10
    cout << S.Camel::m_Age << endl;//  20
}

问题(2):

菱形继承中,SheepCamel子类会继承两份数据,即羊驼获得了10和20两个年龄;这造成了资源浪费,因为我们只需要一份数据,即羊驼是不应该有两个年龄的

解决方法:

利用虚继承即可解决问题。即:将共同基类设置为虚基类

虚基类的定义:class 派生类名 : virtual 继承方式 基类名

class Animal
{
public:int m_Age;
};
class Sheep : virtual public Animal { };
class Camel : virtual public Animal { };
class SheepCamel : public Sheep, public Camel{ };

{
    SheepCamel S;
    S.m_Age = 20;
    S.Sheep::m_Age = 30;
    S.Camel::m_Age = 50;
    cout << "Sheep类中:" << S.Sheep::m_Age << endl;// 50
    cout << "Camel类中:" << S.Camel::m_Age << endl;// 50
    cout << "SheepCamel类中:" << S.m_Age << endl; // 50
}

此时:数据只有一份,类似静态变量,无论是用子类调用还是父类调用都是共享同一份数据。也可以理解为:不管给哪个赋值都是给同一个变量赋值,所以最后等于后赋的值

底层原理:

我们可以通过对象模型来直观理解

在visual studio code  下:利用开发人员命令提示工具查看对象模型(我使用的是vs2022)

1.找到开发人员命令提示工具

2.输入 cd空格+当前源文件的路径(若是C盘,直接输入即可,若是F盘,先 F:转入F盘)

当前源文件的路径获取方法:

最后:输入到开发人员命令提示工具 (输入 cd空格+当前源文件的路径)

3.输入dir,进行查看当前目录是否有当前源文件

4.有当前源文件,继续查找当前SheepCamel类的对象模型布局

输入:cl /d1 reportSingleClassLayout+查找类名 当前源文件名

输入:cl /d1 reportSingleClassLayoutSheepCamel 源.cpp

未设置为虚基类时:

我们可以发现Sheep类的字节大小为8个字节,分别继承于Sheep类、Camel类的成员变量m_Age;

的确是继承了两份数据。

设置为虚基类时:

我们可以发现Sheep类的字节大小为12个字节,分别是Sheep类的虚基类指针、Camel类的虚基类指针,子类继承的m_Age;

此时,只继承了一份数据。

总结:在虚基类中,继承仅有的一份数据存储于子类,可以通过 虚基类指针访问子类来修改其数据的值,或者 子类对象本身来修改。

这篇关于利用虚继承解决菱形继承(钻石继承)的问题 学习笔记的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/514892

相关文章

Feign Client超时时间设置不生效的解决方法

《FeignClient超时时间设置不生效的解决方法》这篇文章主要为大家详细介绍了FeignClient超时时间设置不生效的原因与解决方法,具有一定的的参考价值,希望对大家有一定的帮助... 在使用Feign Client时,可以通过两种方式来设置超时时间:1.针对整个Feign Client设置超时时间

SpringBoot首笔交易慢问题排查与优化方案

《SpringBoot首笔交易慢问题排查与优化方案》在我们的微服务项目中,遇到这样的问题:应用启动后,第一笔交易响应耗时高达4、5秒,而后续请求均能在毫秒级完成,这不仅触发监控告警,也极大影响了用户体... 目录问题背景排查步骤1. 日志分析2. 性能工具定位优化方案:提前预热各种资源1. Flowable

springboot循环依赖问题案例代码及解决办法

《springboot循环依赖问题案例代码及解决办法》在SpringBoot中,如果两个或多个Bean之间存在循环依赖(即BeanA依赖BeanB,而BeanB又依赖BeanA),会导致Spring的... 目录1. 什么是循环依赖?2. 循环依赖的场景案例3. 解决循环依赖的常见方法方法 1:使用 @La

Spring事务中@Transactional注解不生效的原因分析与解决

《Spring事务中@Transactional注解不生效的原因分析与解决》在Spring框架中,@Transactional注解是管理数据库事务的核心方式,本文将深入分析事务自调用的底层原理,解释为... 目录1. 引言2. 事务自调用问题重现2.1 示例代码2.2 问题现象3. 为什么事务自调用会失效3

mysql出现ERROR 2003 (HY000): Can‘t connect to MySQL server on ‘localhost‘ (10061)的解决方法

《mysql出现ERROR2003(HY000):Can‘tconnecttoMySQLserveron‘localhost‘(10061)的解决方法》本文主要介绍了mysql出现... 目录前言:第一步:第二步:第三步:总结:前言:当你想通过命令窗口想打开mysql时候发现提http://www.cpp

SpringBoot启动报错的11个高频问题排查与解决终极指南

《SpringBoot启动报错的11个高频问题排查与解决终极指南》这篇文章主要为大家详细介绍了SpringBoot启动报错的11个高频问题的排查与解决,文中的示例代码讲解详细,感兴趣的小伙伴可以了解一... 目录1. 依赖冲突:NoSuchMethodError 的终极解法2. Bean注入失败:No qu

springboot报错Invalid bound statement (not found)的解决

《springboot报错Invalidboundstatement(notfound)的解决》本文主要介绍了springboot报错Invalidboundstatement(not... 目录一. 问题描述二.解决问题三. 添加配置项 四.其他的解决方案4.1 Mapper 接口与 XML 文件不匹配

MySQL新增字段后Java实体未更新的潜在问题与解决方案

《MySQL新增字段后Java实体未更新的潜在问题与解决方案》在Java+MySQL的开发中,我们通常使用ORM框架来映射数据库表与Java对象,但有时候,数据库表结构变更(如新增字段)后,开发人员可... 目录引言1. 问题背景:数据库与 Java 实体不同步1.1 常见场景1.2 示例代码2. 不同操作

Python中ModuleNotFoundError: No module named ‘timm’的错误解决

《Python中ModuleNotFoundError:Nomodulenamed‘timm’的错误解决》本文主要介绍了Python中ModuleNotFoundError:Nomodulen... 目录一、引言二、错误原因分析三、解决办法1.安装timm模块2. 检查python环境3. 解决安装路径问题

如何解决mysql出现Incorrect string value for column ‘表项‘ at row 1错误问题

《如何解决mysql出现Incorrectstringvalueforcolumn‘表项‘atrow1错误问题》:本文主要介绍如何解决mysql出现Incorrectstringv... 目录mysql出现Incorrect string value for column ‘表项‘ at row 1错误报错