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

C++ 虚继承

C++棱形继承

在 C++ 中,在使用 多继承 时,如果发生了如果类 A 派生出类 B 和类 C,类 D 继承自类 B 和类 C,这时候就发生了菱形继承。

如果发生了菱形继承,这个时候类 A 中的 成员变量 和 成员函数 继承到类 D 中变成了两份

一份来自 A–>B–>D 这条路径,另一份来自 A–>C–>D 这条路径。如下图所示:

在这里插入图片描述
在一个派生类中保留间接基类的多份同名成员,虽然可以在不同的成员变量中分别存放不同的数据,但大多数情况下这是多余的:因为保留多份成员变量不仅占用较多的存储空间,还容易产生命名冲突

假如类 A 有一个成员变量 a,那么在类 D 中直接访问 a 就会产生歧义,编译器不知道它究竟来自 A -->B–>D 这条路径,还是来自 A–>C–>D 这条路径

为了解决菱形继承出现的数据冗余的问题,C++ 提出了虚继承,虚继承使得派生类中只保留一份间接基类的成员

C++虚继承

虚继承的目的是让某个类做出声明,承诺愿意共享它的基类

其中,这个被共享的基类就称为虚基类(Virtual Base Class),菱形继承中的顶层类 就是一个虚基类

在这种机制下,不论虚基类在继承体系中出现了多少次,在派生类中都只包含一份虚基类的成员

虚继承关系,如下图所示:

在这里插入图片描述
观察这个新的继承体系,我们会发现虚继承的一个不太直观的特征:

必须在虚派生的真实需求出现前就已经完成虚派生的操作。在上图中,当定义 D 类时才出现了对虚派生的需求,但是如果 B 类和 C 类不是从 A 类虚派生得到的,那么 D 类还是会保留 A 类的两份成员。

换个角度讲,虚派生只影响从指定了虚基类的派生类中进一步派生出来的类,它不会影响派生类本身。

在实际开发中,位于中间层次的基类将其继承声明为虚继承一般不会带来什么问题。通常情况下,使用虚继承的类层次是由一个人或者一个项目组一次性设计完成的。对于一个独立开发的类来说,很少需要基类中的某一个类是虚基类,况且新类的开发者也无法改变已经存在的类体系。

C++ 标准库中的 iostream 类就是一个虚继承的实际应用案例。iostreamistreamostream 直接继承而来,而 istreamostream 又都继承自一个共同的名为 base_ios 的类,是典型的菱形继承。此时 istreamostream 必须采用虚继承,否则将导致 iostream 类中保留两份 base_ios 类的成员。

iostream 继承体系如下图:

在这里插入图片描述

使用案例:

#include <iostream>
using namespace std;
// 间接基类A
class A
{
protected:int m_a;
};
// 直接基类B
class B: virtual public A
{
protected:int m_b;
};
// 直接基类C
class C: virtual public A
{
protected:int m_c;
};
//派生类D
class D: public B, public C
{
public:void seta(int a){ m_a = a;   //命名冲突}void setb(int b){ m_b = b;   //正确}void setc(int c){ m_c = c;   //正确}  void setd(int d){ m_d = d;   //正确}  
private:int m_d;
};
int main()
{cout << "嗨客网(www.haicoder.net)\n" << endl;D d;return 0;
}

C++虚继承构造函数

普通的 继承 时,我们可以在子类直接显式的调用父类的 构造函数,在 虚继承 中,虚基类是由最终的派生类初始化的。

也就是说,最终派生类的构造函数必须要调用虚基类的构造函数

对最终的派生类来说,虚基类是间接基类,而不是直接基类。这跟普通继承不同,在普通继承中,派生类构造函数中只能调用直接基类的构造函数,不能调用间接基类的。

相关文章:

C++ 虚继承

C棱形继承 在 C 中&#xff0c;在使用 多继承 时&#xff0c;如果发生了如果类 A 派生出类 B 和类 C&#xff0c;类 D 继承自类 B 和类 C&#xff0c;这时候就发生了菱形继承。 如果发生了菱形继承&#xff0c;这个时候类 A 中的 成员变量 和 成员函数 继承到类 D 中变成了两…...

git commit用法

git commit 是 Git 版本控制系统中的一个命令&#xff0c;用于将更改提交到本地存储库。以下是 git commit 的一些常见用法和选项&#xff1a; 基本用法: git commit -m "提交信息"使用 -m 选项可以直接在命令行中添加提交信息。 提交所有更改: git commit -a -m &q…...

【LeetCode】543.二叉树的直径

题目 给你一棵二叉树的根节点&#xff0c;返回该树的 直径 。 二叉树的 直径 是指树中任意两个节点之间最长路径的 长度 。这条路径可能经过也可能不经过根节点 root 。 两节点之间路径的 长度 由它们之间边数表示。 示例 1&#xff1a; 输入&#xff1a;root [1,2,3,4,5]…...

TypeScript教程(五)条件语句,循环,函数

一、条件语句 条件语句基于不同的条件来执行不同的动作 1.if语句&#xff1a;只有当指定条件为true时&#xff0c;使用该语句来执行代码 2.if...else语句&#xff1a;当条件为true时执行代码&#xff0c;当条件为else时执行其他代码 3.if...else if...else语句&#xff1a;…...

vue使用jsplumb 流程图

安装jsPlumb库&#xff1a;在Vue项目中使用npm或yarn安装jsPlumb库。 npm install jsplumb 创建一个Vue组件&#xff1a;创建一个Vue组件来容纳jsPlumb的功能和呈现。 <template><div style"margin: 20px"><div style"margin: 20px">&l…...

【BASH】回顾与知识点梳理(二十八)

【BASH】回顾与知识点梳理 二十八 二十八. 例行性工作排程(crontab)28.1 什么是例行性工作排程Linux 工作排程的种类&#xff1a; at, cronCentOS Linux 系统上常见的例行性工作 28.2 仅执行一次的工作排程atd 的启动at 的运作方式实际运作单一工作排程at 工作的管理batch&…...

LangChain源码逐行解密之系统(二)

LangChain源码逐行解密之系统 20.2 serapi.py源码逐行剖析 我们可以看一下Google查询的例子,在LangChain中有多种实现的方式。 如图20-5所示,在utilities的serpapi.py代码文件中实现了SerpAPIWrapper。 图20- 5 utilities的serpapi.py的SerpAPIWrapper 在langchain目录的se…...

QT的设计器介绍

设计器介绍 Qt制作 UI 界面&#xff0c;一般可以通过UI制作工具QtDesigner和纯代码编写两种方式来实现。纯代码实现暂时在这里不阐述了在后续布局章节详细说明&#xff0c;QtDesigner已经继承到开发环境中&#xff0c;在工程中直接双击ui文件就可以直接在QtDesigner设计器中打…...

[LitCTF 2023]Ping

因为直接ping会有弹窗。这里在火狐f12,然后f1选禁用javascript,然后ping 然后输入127.0.0.1;cat /flag 得到flag&#xff0c; 查看其他大佬的wp &#xff0c;这里还可以抓包。但是不知道为什么我这里的burp 用不了...

Spring Cloud面试突击班1

Spring Cloud面试突击班1 1.Spring Cloud 中有哪些组件&#xff0c;整个项目架构中我们的重点又有哪些&#xff1f; Spring Cloud 是一套基于Spring Boot的微服务解决方案。 Spring Cloud生态在国内主流的分为两套&#xff0c;一套是以奈飞开源的Spring Cloud Netfilx 20%&a…...

线上售楼vr全景看房成为企业数字化营销工具

在房地产业中&#xff0c;VR全景拍摄为买家提供了虚拟看房的全新体验。买家可以通过相关设备&#xff0c;远程参观各个楼盘的样板间和实景&#xff0c;感受房屋的空间布局和环境氛围&#xff0c;极大地提高了购房决策的准确性。对于房地产开发商和中介机构来说&#xff0c;VR全…...

“深入探索JVM内部机制:解密Java虚拟机原理“

标题&#xff1a;深入探索JVM内部机制&#xff1a;解密Java虚拟机原理 摘要&#xff1a;本文将深入探索Java虚拟机&#xff08;JVM&#xff09;的内部机制&#xff0c;揭示其工作原理和关键组成部分&#xff0c;包括类加载、内存管理、垃圾回收、即时编译和运行时数据区域等。…...

最长 上升子序列

大家好 我是寸铁 希望这篇题解对你有用&#xff0c;麻烦动动手指点个赞或关注&#xff0c;感谢您的关注 不清楚蓝桥杯考什么的点点下方&#x1f447; 考点秘籍 想背纯享模版的伙伴们点点下方&#x1f447; 蓝桥杯省一你一定不能错过的模板大全(第一期) 蓝桥杯省一你一定不…...

Nginx的介绍

本资料转载于传智教育-解锁你的IT职业薪未来&#xff0c;仅用于学习和讨论&#xff0c;如有侵权请联系 视频地址&#xff1a;04-Nginx的优点_哔哩哔哩_bilibili 资源文档&#xff1a;链接&#xff1a;https://pan.baidu.com/s/1RlFl92FdxRUqc858JSxPSQ 提取码&#xff1a;12…...

[杂项]奥特曼系列影视列表大全

1966年&#xff1a;《奥特曼》「初代奥特曼」 1967年&#xff1a;《奥特赛文》 1971年&#xff1a;《归来的奥特曼》「杰克奥特曼」 1972年&#xff1a;《艾斯奥特曼》 1973年&#xff1a;《泰罗奥特曼》 1974年&#xff1a;《雷欧奥特曼》 1979年动画版&#xff1a;《乔尼亚斯…...

java代码日记--java 基础语法

java代码日记 在线运行 本地运行环境配置 Java 实例 实战 java8 Java 基础语法 一个Java程序可以认为是一系列对象的集合&#xff0c;而这些对象通过调用彼此的方法来协同工作。 下面简要介绍下类、对象、方法和实例变量的概念。 对象&#xff1a;对象是类的一个实例&…...

Spring中的IOC与DI-细胞内物质与传递

对IOC的认识 Spring Inversion of Control简称Spring IOC&#xff0c;是一种设计原则&#xff0c;通过它可以实现对象之间的解耦。通过Spring DI(Dependency Injection)依赖注入实现对象生命周期管理&#xff0c;为开发者提供对象创建、使用方式。 Spring中的Bean 在Spring框…...

【探索Linux】—— 强大的命令行工具 P.5(yum工具、git 命令行提交代码)

阅读导航 前言一、软件包管理器 yum1.yum的概念yum的基本指令使用例子 二、git 命令行提交代码总结温馨提示 前言 前面我们讲了C语言的基础知识&#xff0c;也了解了一些数据结构&#xff0c;并且讲了有关C的一些知识&#xff0c;也学习了一些Linux的基本操作&#xff0c;也了…...

jdbc 使用rewriteBatchedStatements=true后,报错

jdbc 使用rewriteBatchedStatementstrue后&#xff0c;报错了 rewriteBatchedStatementstrue解释 rewriteBatchedStatementstrue是一个配置选项&#xff0c;它影响MySQL JDBC驱动程序的行为。JDBC是Java数据库连接的标准。当你使用Java程序连接MySQL数据库时&#xff0c;你需要…...

第G1周:生成对抗网络(GAN)入门

&#x1f368; 本文为[&#x1f517;365天深度学习训练营]内部限免文章&#xff08;版权归 *K同学啊* 所有&#xff09; &#x1f356; 作者&#xff1a;[K同学啊] 一、理论基础 生成对抗网络&#xff08;Generative Adversarial Networks, GAN&#xff09;是近年来深度学习领域…...

MPNet:旋转机械轻量化故障诊断模型详解python代码复现

目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...

云计算——弹性云计算器(ECS)

弹性云服务器&#xff1a;ECS 概述 云计算重构了ICT系统&#xff0c;云计算平台厂商推出使得厂家能够主要关注应用管理而非平台管理的云平台&#xff0c;包含如下主要概念。 ECS&#xff08;Elastic Cloud Server&#xff09;&#xff1a;即弹性云服务器&#xff0c;是云计算…...

day52 ResNet18 CBAM

在深度学习的旅程中&#xff0c;我们不断探索如何提升模型的性能。今天&#xff0c;我将分享我在 ResNet18 模型中插入 CBAM&#xff08;Convolutional Block Attention Module&#xff09;模块&#xff0c;并采用分阶段微调策略的实践过程。通过这个过程&#xff0c;我不仅提升…...

Java如何权衡是使用无序的数组还是有序的数组

在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...

关于 WASM:1. WASM 基础原理

一、WASM 简介 1.1 WebAssembly 是什么&#xff1f; WebAssembly&#xff08;WASM&#xff09; 是一种能在现代浏览器中高效运行的二进制指令格式&#xff0c;它不是传统的编程语言&#xff0c;而是一种 低级字节码格式&#xff0c;可由高级语言&#xff08;如 C、C、Rust&am…...

爬虫基础学习day2

# 爬虫设计领域 工商&#xff1a;企查查、天眼查短视频&#xff1a;抖音、快手、西瓜 ---> 飞瓜电商&#xff1a;京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空&#xff1a;抓取所有航空公司价格 ---> 去哪儿自媒体&#xff1a;采集自媒体数据进…...

实现弹窗随键盘上移居中

实现弹窗随键盘上移的核心思路 在Android中&#xff0c;可以通过监听键盘的显示和隐藏事件&#xff0c;动态调整弹窗的位置。关键点在于获取键盘高度&#xff0c;并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...

JAVA后端开发——多租户

数据隔离是多租户系统中的核心概念&#xff0c;确保一个租户&#xff08;在这个系统中可能是一个公司或一个独立的客户&#xff09;的数据对其他租户是不可见的。在 RuoYi 框架&#xff08;您当前项目所使用的基础框架&#xff09;中&#xff0c;这通常是通过在数据表中增加一个…...

中医有效性探讨

文章目录 西医是如何发展到以生物化学为药理基础的现代医学&#xff1f;传统医学奠基期&#xff08;远古 - 17 世纪&#xff09;近代医学转型期&#xff08;17 世纪 - 19 世纪末&#xff09;​现代医学成熟期&#xff08;20世纪至今&#xff09; 中医的源远流长和一脉相承远古至…...

智能AI电话机器人系统的识别能力现状与发展水平

一、引言 随着人工智能技术的飞速发展&#xff0c;AI电话机器人系统已经从简单的自动应答工具演变为具备复杂交互能力的智能助手。这类系统结合了语音识别、自然语言处理、情感计算和机器学习等多项前沿技术&#xff0c;在客户服务、营销推广、信息查询等领域发挥着越来越重要…...