C++:多继承虚继承

在C++中,虚继承(Virtual Inheritance)是一种特殊的继承方式,用于解决菱形继承(Diamond Inheritance)问题。菱形继承指的是一个类同时继承自两个或更多个具有共同基类的类,从而导致了多个实例同一个基类的实例的冗余。

多继承-菱形继承

现在来思考以下经典的菱形继承问题:

     Animal
      / \
    cat  bear
      \ /
      panda

在这个继承结构中,类 Animal 是基类,类 catbear 都直接继承自 Animal,而类 panda 继承自 catbear。当使用传统的继承方式时,panda 类将会继承两份 Animal 类的实例,这会导致冗余。

以下代码就是典型的菱形继承的例子:
class Animal
{
public:
    Animal();
    ~Animal();
    int m_nAge;
};
​
​
class Cat : public Animal
{
public:
    Cat();
    ~Cat();
};
​
class bear:public Animal
{
public:
    bear();
    ~bear();
};
​
class Panda:public Cat,public bear
{
public:
    Panda();
    ~Panda();
};

AnimalAnimal 类是一个基类,具有一个 m_nAge 成员变量,用于表示动物的年龄。

Cat 类和 bearCat 类和 bear 类分别是 Animal 类的公有派生类。它们继承了 Animal 类的成员变量和方法。

PandaPanda 类同时公有派生自 Cat 类和 bear 类,从而继承了这两个类的成员。由于 Cat 类和 bear 类都是从 Animal 类继承而来的,因此 Panda 类实际上包含了两份 Animal 类的成员变量 m_nAge,这导致冗余数据。

在构造函数中设置标志,创建panda对象后得到的结果:创建一个Panda对象,Animal构造了两次。

此时我在主程序中进行panda对象的创建,并尝试对panda继承下来的的m_nAge对象进行赋值:

此时程序报错,并提示Pandam_nAge成员不明确,原因其实就是因为Panda 继承自Catbear两个类,那么就意味着Panda类继承了两份 Animal 类的成员变量 m_nAge,此时使用panda->m_nAge = 10;Panda的变量进行赋值编译器就会混淆;如果不想程序爆红就在赋值时就必须成员变量的继承来源:

int main() {
    Panda * panda = new Panda;
    //成员变量的赋值
    panda->Cat::m_nAge = 10;
    panda->bear::m_nAge = 15;
​
    std::cout << "Panda Age:" << panda->Cat::m_nAge << "  Panda AgeB:" << panda->bear::m_nAge << std::endl;
    delete panda;
    system("pause");
    return 0;
}

panda->Cat::m_nAge = 10;:给 panda 对象中 Cat 类的成员变量 m_nAge 赋值为 10

panda->bear::m_nAge = 15;:给 panda 对象中 bear 类的成员变量 m_nAge 赋值为 15

就算解决了程序不报错的问题其实菱形继承(多继承)时还会出现其他问题:

1.数据冗余:每个派生类实例都会包含基类实例的副本,这可能会导致内存空间的浪费,特别是在多重继承的情况下,可能会存在多份相同的基类数据。
2.数据一致性:如果多个派生类实例共享同一个基类实例,那么当修改其中一个派生类实例中的基类数据时,会影响到其他共享同一基类实例的派生类实例,这可能会导致数据不一致的问题。
3.维护困难:当多个派生类实例共享同一个基类实例时,可能会增加代码的复杂性和维护成本,因为需要确保在任何修改基类数据的地方都能正确地处理多个派生类实例。
4.生命周期问题:如果派生类实例在不同的时间点创建和销毁,而共享的基类实例在某个派生类实例被销毁后还继续存在,这可能会导致悬挂指针或内存泄漏等问题

这个时候就可以使用虚继承对以上问题进行统一解决;

虚继承

虚继承通过使用关键字 virtual 来解决这个问题。当一个类以虚继承方式继承自一个基类时,无论该类被多次继承,其基类的实例只会在继承层次结构中的最顶层被创建一次。这意味着,对于上面的菱形继承问题,使用虚继承后,D 类将只继承一份 A 类的实例。

回到上述例子:

class Animal
{
public:
    Animal();
    ~Animal();
​
    int m_nAge;
}
​
//使用虚继承
class Cat : public virtual Animal
{
public:
    Cat();
    ~Cat();
};
​
//使用虚继承
class bear:public virtual Animal
{
public:
    bear();
    ~bear();
​
};
​
class Panda:public Cat,public bear
{
public:
    Panda();
    ~Panda();
​
};

Cat 类和 bear:这两个类都使用了虚继承,即使用 virtual 关键字来继承自 Animal 类。这意味着无论 Cat 类和 bear 类被多次继承,Animal 类的实例都只会在继承层次结构中的最顶层被创建一次。这样可以避免在 Panda 类中出现多个 Animal 类的实例,从而解决了菱形继承问题。

PandaPanda 类同时公有派生自 Cat 类和 bear 类,从而继承了这两个类的成员。因为 Cat 类和 bear 类都是虚继承自 Animal 类的,所以 Panda 类中只包含了一个 Animal 类的实例,从而避免了多个实例共享同一个基类实例的冗余问题。

这就意味着此时我们在主函数中创建panda对象,并对对象的m_nAge成员进行赋值/访问:

int main() {
    Panda * panda = new Panda;
    panda->m_nAge = 10;
    std::cout << "Panda Age:" << panda->m_nAge << std::endl;
    delete panda;
}

运行结果:

Panda Age:10

panda对象中的m_nAge成员变量就只有一个副本,这个时候就对对象中的成员进行访问时就无需再指定继承路径了。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

20240507最新 ubuntu20.04安装ros noetic

ubuntu20.04安装ros 主要参考博客 【ROS】在 Ubuntu 20.04 安装 ROS 的详细教程_ubuntu20.04安装ros-CSDN博客 出现问题 1.ubuntu20.04 更换清华源报错 ubuntu20.04 更换清华源报错_gvfs metadata is not supported. fallback to teplme-CSDN博客 &#xff1f;&#xff1f…

汽车 - 什么是车轮抱死

车轮抱死分为两种情况&#xff0c;一种是车辆故障层面&#xff0c;另一种是驾驶过程中的物理现象。我们先来说最通俗的刹车车轮抱死吧。 刹车制动车轮抱死 车轮停止轴向转动就是抱死&#xff0c;有速度的情况下抱死车轮&#xff0c;如果车辆的惯性动能大于轮胎抓地力&#xff0…

Springboot集成Mybatispuls操作mysql数据库-03

MyBatis-Plus&#xff08;简称MP&#xff09;是一个MyBatis的增强工具&#xff0c;在MyBatis的基础上只做增强而不做改变。它支持所有MyBatis原生的特性&#xff0c;因此引入MyBatis-Plus不会对现有的MyBatis构架产生任何影响。MyBatis-Plus旨在简化开发、提高效率&#xff0c;…

基于FPGA的去雾算法

去雾算法的原理是基于图像去模糊的原理&#xff0c;通过对图像中的散射光进行估计和去除来消除图像中的雾霾效果。 去雾算法通常分为以下几个步骤&#xff1a; 1. 导引滤波&#xff1a;首先使用导引滤波器对图像进行滤波&#xff0c;目的是估计图像中散射光的强度。导引滤波器…

MATLAB绘制蒸汽压力和温度曲线

蒸汽压力与温度之间的具体关系公式一般采用安托因方程&#xff08;Antoine Equation&#xff09;&#xff0c;用于描述纯物质的蒸汽压与温度之间的关系。安托因方程的一般形式如下&#xff1a; [\log_{10} P A - \frac{B}{C T}] 其中&#xff0c; (P) 是蒸汽压&#xff08…

安卓view坐标系

目录 一、getX、 getRawX、 getTranslationX 等的图形表示二、 getX、 getRawX、 getTranslationX 意义的文字描述 一、getX、 getRawX、 getTranslationX 等的图形表示 坐标系&#xff1a; 视图坐标系&#xff1a; 二、 getX、 getRawX、 getTranslationX 意义的文字描述 …

【吊打面试官系列】Java高并发篇 - volatile 变量和 atomic 变量有什么不同?

大家好&#xff0c;我是锋哥。今天分享关于 【volatile 变量和 atomic 变量有什么不同&#xff1f;】面试题&#xff0c;希望对大家有帮助&#xff1b; volatile 变量和 atomic 变量有什么不同&#xff1f; Volatile 变量可以确保先行关系&#xff0c;即写操作会发生在后续的读…

Vue 插槽

Vue插槽是一种特殊的语法&#xff0c;用于在组件中定义可复用的模板部分。它允许开发者在组件的标记中声明一个或多个插槽&#xff0c;然后在使用该组件时&#xff0c;可以根据自己的需求将内容插入到这些插槽中。 Vue插槽分为默认插槽和具名插槽两种。 默认插槽 语法 组件…

中国科技大航海时代,“掘金”一带一路

文&#xff5c;白 鸽 编&#xff5c;王一粟 “这不就是90年代的内地吗&#xff1f;” 在深度考察完沙特市场后&#xff0c;华盛集团联合创始人兼CEO张霆对镜相工作室感慨道。 在张霆看来&#xff0c;沙特落后的基建&#xff08;意味着大量创新空间&#xff09;、刚刚开放…

18.Blender 渲染工程、打光方法及HDR贴图导入

HDR环境 如何导入Blender的HDR环境图 找到材质球信息 在右上角&#xff0c;点击箭头&#xff0c;展开详细部分 点击材质球&#xff0c;会出现下面一列材质球&#xff0c;将鼠标拖到第二个材质球&#xff0c;会显示信息 courtyard.exr 右上角打开已渲染模式 左边这里选择世界…

01、JMS规范介绍

01、JMS规范介绍 在我们正式学习Kafka之前&#xff0c;先来了解下JMS&#xff0c;因为这可以在一定程度上帮助你更加深入的理解和学习Kafka。 1、 JMS简介 JMS&#xff0c;全称Java Mesage Service&#xff0c;即Java消息服务应用程序接口&#xff0c;是一个Java平台中关于面…

HIVE统计WordCount

HIVE WORDCOUNT 目录 HIVE WORDCOUNT 一、WORDCOUNT 1.我们先创建一个新的数据库 2.创建表并插入数据 3.统计WORDCOUNT 4.UNION ALL 用法 5.WITH AS 用法 1.WORDCOUNT 1&#xff09;我们先创建一个新的数据库 create database learn3;use learn3; 2&#xff09;创建表…

产品推荐 | 基于 Virtex UltraScale+ XCVU3P的FACE-VPXSSD-3PA 存储板

01 产品概述 FACE&#xff08;FPGA Algorithm aCceleration Engine&#xff09;FPGA算法加速开发引擎是基于FPGA可编程器件构建的一系列算法加速开发引擎平台。FACE-VPXSSD-3PA存储平台是FACE系列中的一员。该平台板载2组2GB 64bit DDR4、2路QSFP28光接口、4个NVME SSD M.2接口…

yum常用命令与lrzsz的在线安装

yum命令 yum&#xff08; Yellow dog Updater, Modified&#xff09;是一个在 Fedora 和 RedHat 以及 SUSE 中的 Shell 前端软件包管理器。 基于 RPM 包管理&#xff0c;能够从指定的服务器自动下载 RPM 包并且安装&#xff0c;可以自动处理依赖性关系&#xff0c;并且一次安装…

设备驱动中device_create函数与sys/devices目录

当调用device_create时parent参数为空时&#xff0c;新添加的设备位于sys/devices//sys/devices/virtual目录 以下面代码的为例 my_newcharled.myclass class_create(THIS_MODULE,dtled); my_newcharled.mydevice device_create(my_newcharled.myclass,NULL,my_newcharled.ne…

04-19 周五 GitHub actions-runner 程序解释

04-19 周五 GitHub actions-runner 程序解释 时间版本修改人描述2024年4月19日17:26:17V0.1宋全恒新建文档 简介 本文主要描述了actions-runner-linux-x64-2.315.0.tar.gz这个github actions CI所需要的客户端安装包的重要文件和内容信息。有关GitHub actions 的配置&#xff…

天图通逊|塘厦总仓服务全面升级

尊敬的客户&#xff1a; 您好!为了提供更优质、更高效的物流服务品质&#xff0c;我司针对国内塘厦仓库进行全面优化升级。升级内容如下&#xff1a; 1.分拣设备升级&#xff1a;在原有的自动分拣设备进行升级&#xff0c;由1.0速升级为1.5高速版&#xff1b;将分拣口的数量从…

<网络安全>《77 概念讲解<第十课 物联网常用协议-(近距离通信)感应层协议>》

协议简称全称名称内容说明RFIDRadio Frequency Identification射频识别阅读器与标签之间进行非接触式的数据通信&#xff0c;达到识别目标的目的。RFID的应用非常广泛&#xff0c;典型应用有动物晶片、汽车晶片防盗器、门禁管制、停车场管制、生产线自动化、物料管理。完整的RF…

基于数字证书的移动终端金融安全身份认证规范

基于数字证书的移动终端金融安全身份认证规范 1 范围 本文件规定了基于数字证书的移动终端金融安全身份认证的服务描述、移动终端生命周期管理、服 务生命周期管理、密钥管理、安全及功能、风险控制和运营管理的要求。 本文件适用于银行业金融机构、非银行支付机构&#xff0c…

1.4 初探JdbcTemplate操作

实战目的 掌握Spring框架中JdbcTemplate的使用&#xff0c;实现对数据库的基本操作。理解数据库连接池的工作原理及其在实际开发中的重要性。通过实际操作&#xff0c;加深对Spring框架中ORM&#xff08;对象关系映射&#xff09;的理解。 关键技术点 JdbcTemplate操作&…