C++·继承
面向对象编程有三大特性:封装、继承、多态。
封装我们前几节已经讲过了,第一层封装是将一个数据和方法都封装到一个类中,想让用户访问的定义成公有,不想让用户访问的定义成私有,第二层封装就类似于迭代器、适配器的思想,将各种容器的访问方法都封装成迭代器,让用户使用容器的时候不用关心底层的细节或访问的方式,只需要迭代器就可以使用各种容器了。
1. 继承的概念和定义
1.1 继承的定义
继承(inheritance)机制是面向对象程序设计使代码可以复用的重要手段,它允许程序员在保持原有类特性的基础上进行拓展,增加功能,这样产生新的类,称为派生类或子类,原有类称为基类或父类。
比如我们想维护学生和老师两个类,但这两个类有姓名和年龄两个相同的成员变量,但分别又有学号和工号两个不同的成员变量。此时我们就可以考虑让这两个类继承另一个Person类的内容。

继承的语法就是在派生类的类名后面加上 :+继承方式+基类 此时Person类中的内容就被继承给了Student和Teacher类。
我们可以验证一下:

可以看到派生类实例化后可以使用基类的各种内容了,说明父类已经将自己的所有内容继承给了子类。
1.2 继承后的访问方式变化
继承的操作就像是把基类的所有内容拷贝进了派生类,而不用让我们自己 C+V 过去,但是根据基类成员的访问限定类型和继承方式的不同,拷贝进派生类后的成员也会获得新的访问限定类型。
可以看到Person类的成员变量的访问限定方式我选择的是 proteced 而不是我们之前经常写的 private ,这是因为我认为Student和Teacher类中需要修改继承过来的这两个成员变量,而如果在父类中将这两个成员变量定义成 private 那么在子类中这两个成员变量就变成了不可见状态,不可见状态就是说在子类中无法访问或修改这两个成员。


可以看到当父类中的private内容被继承给子类后,子类就无法对其访问或修改。
但是不可见状态并不是不存在,这个要东西理解一下,就是当我们不通过子类访问不可见内容是可以做到的。

可以看到在这段代码中,两个子类的实例化还是可以通过父类的成员函数来访问到对于他俩来说的不可见成员。
好了解释完不可见状态之后我们来看一下继承后的访问方式变化到底是怎么变的

总结:
1. 基类的private成员在派生类中无论以何种方式继承都是不可见的。
2. 基类其他成员在派生类中的访问方式取 min(基类成员访问限定符,继承方式),其中public>protected>private
3. 在实际运用中一般都是用 public继承。
最后在提一下父类的private成员问题,当父类的某个成员是private成员,其实当时设定的时候就是不想让子类能访问到这个成员,因此才设置成private的,仅父类可访问。
2. 基类和派生类对象赋值兼容转换
我们看上面这段代码,很怪,将派生类直接赋值给了父类。
派生对象 可以赋值給 基类对象、基类指针、基类引用。这种操作有种形象的叫法,叫做切割。就是说把派生类中的父类那部分切割下来给过去。或者用更专业的叫法,赋值兼容转换
基类对象不能赋值给派生对象。
我们之前有学过一种和这个很像的操作也是在两个不同类型的变量之间赋值,我们管那种操作叫 截断---整型提升。但是这个切割是特殊的,截断整型提升在操作的中间会产生临时变量,但是切割不会。

如果是把子类中属于父类那块的地址切割下来给到一个父类的实例化,或者把子类中属于父类那块的引用切割下来给到一个父类的实例化,通过更改父类的实例化都可以起到修改到子类的效果。
3. 继承中的作用域
1 .在继承体系中基类和派生类都有独立的作用域
2. 基类和派生类中的同名成员,子类成员将屏蔽父类对同名成员的直接访问,这种情况叫做隐藏。如果想在子类中访问父类的同名成员,就要 父类::成员名 显示访问。
3. 如果是成员函数的隐藏,只需要同名就可以构成隐藏,不需要像函数重载那样考虑参数类型。
4. 在实际应用继承体系时尽量不要定义同名的成员,完全在给自己挖坑。
4. 派生类默认成员函数
4.1 默认构造
下面我们看看子类构造的时候其中的父类成员的构造动作是什么。

可以看到当子类使用编译器自动生成的默认构造时,子类实例化的时候会直接调用父类的默认构造。
如果想在子类构造的同时更改一下属于父类的那些成员,就是说显示写子类的默认构造该如何做。

首先要保证父类的构造中可以支持修改这一变量,然后在子类的构造函数初始化列表中调用父类的这个构造函数并附上参数。
这种写法是规定的,之所以有这种规定就是因为当父类已经有构造的时候为了防止子类中瞎搞,所以要求如果像更改父类的成员初始化内容就要通过父类的自己构造,而不是在子类中瞎写。这就像是类中的自定义变量初始化会调用它的默认构造一个道理。父类也可以当子类的一个自定义变量来看待。
4.2 拷贝构造
在不显示写子类的拷贝构造的情况下,编译器自动生成的拷贝构造是会调用父类的拷贝构造的。

那如果我们需要显示写出子类的拷贝构造的时候也要在初始化列表中显示调用父类的拷贝构造,否则编译器会调用父类的默认构造来匹配子类的拷贝构造,结果就是程序正常运行,但是父类的内容没用拷贝过来,其中父类的内容明显是用的默认构造生成的。

这里在使用显示的拷贝构造时,我们就用到了上面的赋值兼容转换概念,将子类中的父类区域切割给父类的拷贝构造当参数使用。
4.3 赋值操作符重载


赋值操作符重载写起来比较简单,唯一需要注意的就是 operator= 在父类和子类之间构成了隐藏关系,因此在子类中要使用父类的operator=需要声明类域。否则会去掉用子类的operator=从而形成无限递归。
当然,这些拷贝构造或者赋值重载都是在需要深拷贝的时候才需要使用的,我们这里写只是介绍用法。
4.4 析构函数


子类析构函数在显示写的时候规定不要去调用父类的析构函数,编译器自己会去调用父类的析构函数,因此子类的析构函数只需解决那些会开空间的变量。
在构造子类对象的时候要遵循先构造父类在构造子类的顺序,因为子类中的某些成员变量在构造的时候可能会用到父类中的一些成员,如果此时先构造子类对象的时候就会出现乱码,因为父类的对象还没有构造生成。但是对于这个问题无需担心,因为构造对象的顺序是根据成员变量的声明顺序走的,而不是参数列表中的顺序,而因为子类是继承了父类而产生的,因此父类永远都比子类先构造。
再说回析构的问题,父类需要比子类后析构,因为子类在析构过程中可能会用到父类中的一些成员,而反过来父类永远不可能用得到子类的成员。但是在实际编写析构的时候, 不会像构造那样因为有语法的规则存在,正好固定的了构造顺序。相反,析构时如果把父类的析构写在子类的析构函数中时,很明显就先析构了父类。为了避免这种情况的出现,于是规定了不用在子类中写父类的析构,编译器会自己在子类析构之后去析构父类。
5. 继承与友元
父类的友元关系不能继承给子类,也就是说父类的友元不能访问子类的私有或保护成员。
6. 继承与静态成员
基类中有一个static静态成员,则整个继承体系中也只有一个这样的成员。无论派生出多少个子类,都只有一个static静态成员。这就不得不回忆起在讲类和对象的时候,对于类的静态成员有一个规则:类中的静态成员变量属于所有类的对象。子类对象中隐含了一个父类对象,自然子类的对象也与父类的对象共用一个静态成员变量。

可以看到,父类对象与子类对象的静态变量是同一块空间,还是印证了前面那个规则。
如果忘记了类中静态成员变量的诸多规则,传送:
C++语言·类和对象(下)-CSDN博客文章浏览阅读801次,点赞15次,收藏22次。本文详细阐述了C++中构造函数、初始化列表、隐式类型转换、explicit关键字、静态成员、友元、内部类和匿名对象的概念,以及编译器在某些场景下的优化策略,帮助读者掌握这些关键概念和实践技巧。https://blog.csdn.net/atlanteep/article/details/137886869?spm=1001.2014.3001.5501
7. 多继承同棱形继承等复杂继承逻辑
单继承:一个子类只继承一个直接父类的继承关系。

多继承:一个子类有两个或以上直接父类的继承关系

菱形继承:菱形继承是多继承的一种特殊情况
菱形继承逻辑存在数据冗余和二义性的问题。
二义性是指,在西红柿类中访问植物类的成员时,如果直接访问就会有蔬菜中的植物类成员变量,还是水果类中的植物类成员变量的歧义,因此想解决这一问题需要指定植物类所在的类域。


数据冗余是指西红柿中存了两份植物的信息,但其实对于西红柿来说只需要一份植物信息就够了,如果当植物类很大时,两份植物类会造成大量的数据冗余问题。C++为了解决这种情况打了一个补丁,使用虚拟继承。

因为现在植物类只在西红柿类中出现了一份,因此现在二义性的问题也随之解决了
虚拟继承要在产生数据冗余的第一时间加上

比如在上面这个逻辑中,要在B、C类的地方就要加上虚拟继承。
其实为了避免这种复杂的情况出现,在设计类的时候我们可以接受多继承,但是尽量不要设计菱形继承。
8. 继承的总结和反思
多继承就是C++语法复杂的一个体现,有了多继承就会出现令行继承,有了菱形继承的问题就要设计出虚拟继承的概念,底层实现就越来越复杂。因此多继承可以认为是C++的缺陷之一,后来的很多语言就没有多继承了,比如JAVA
继承和组合
组合就是说把另一个类通过成员变量手动塞到这个类中,形成组合的关系。
继承是一种 is-a 的关系,就是说每个派生类对象都是基类对象的特殊体。
组合是一种 has-a 的关系,假设B组合了A,那每个B中都有一个A。
根据软工中 高内聚,低耦合 的理念,尽量使用组合结构而不是继承结构,因为组合结构访问不了另一个类的保护对象,因此在结构上相比于继承拥有更低耦合度。
但具体用哪一种还是看具体情况,比如 车轮-车 的关系中就用组合, 蔬菜-西红柿 的关系中就用继承,如果是 链表-队列 这种既可以用组合也可以用继承的关系中当然首选组合。
相关文章:
C++·继承
面向对象编程有三大特性:封装、继承、多态。 封装我们前几节已经讲过了,第一层封装是将一个数据和方法都封装到一个类中,想让用户访问的定义成公有,不想让用户访问的定义成私有,第二层封装就类似于迭代器、适配器的思想…...
2024最适合小白的Midjourney教程,值得收藏!
一、Midjourney 的提示词 1、提示可以包括一个或多个图像 URL、多个文本短语以及一个或多个参数 1)Image Prompts(图像提示):可以将图像 URL 添加到提示中以影响最终结果的样式和内容。图像 URL 始终出现在提示的前面。文件应以.…...
MVC 返回集合方法,以及分页
返回一个数据集方法 返回多个数据集方法 》》定义一个Model public class IndexMoel {public List<UserGroup> UserGroup{get;set;}public List<User> User{get;set;}}》》》控制器 //db 是 EF 中的上下文 var listnew IndexModel(); list.UserGroupdb.UserGro…...
昇思MindSpore学习笔记6-05计算机视觉--SSD目标检测
摘要: 记录MindSpore AI框架使用SSD目标检测算法对图像内容识别的过程、步骤和方法。包括环境准备、下载数据集、数据采样、数据集加载和预处理、构建模型、损失函数、模型训练、模型评估等。 一、概念 1.模型简介 SSD目标检测算法 Single Shot MultiBox Detecto…...
vb.netcad二开自学笔记9:界面之ribbon
一个成熟的软件怎么能没有ribbon呢,在前面的框架基础上再加个命令AddRibbon <CommandMethod("AddRibbon")> Public Sub AddRibbon() Dim ribbonControl As RibbonControl ComponentManager.Ribbon Dim tab As RibbonTab New RibbonTab() tab.Tit…...
学习笔记——动态路由——OSPF链路状态通告(LSA)
十、OSPF链路状态通告(LSA) 1、链路状态通告简介 (1)LAS概述 链路状态通告(Link State Advertisement,LSA)是路由器之间链路状态信息的载体。LSA是LSDB的最小组成单位,LSDB由一条条LSA构成的。是OSPF中计算路由的重要依据。 LSA用于向其它邻接OSPF路…...
模拟防止重复提交
gitee地址(需要自取)AopProxy重复提交: 防止重复提交 (gitee.com) RestController public class SubmissionController {Autowiredprivate SubmissionService submissionService;private static Jedis jedis new Jedis("localhost",6379);pr…...
C++:strcut与class的区别
在C中,struct和class在语法上非常相似,但它们之间确实存在一些关键的差异,这些差异主要体现在成员的默认访问权限和继承的默认方式上。然而,从更广泛的角度来看,它们都可以用来定义自定义数据类型,包含数据…...
科研绘图系列:R语言两组数据散点分布图(scatter plot)
介绍 展示两组数据的散点分布图是一种图形化表示方法,用于显示两个变量之间的关系。在散点图中,每个点代表一个数据点,其x坐标对应于第一组数据的值,y坐标对应于第二组数据的值。以下是散点图可以展示的一些结果: 线性关系:如果两组数据之间存在线性关系,散点图将显示出…...
【EasyExcel】根据单元格内容自动调整列宽
1.自定义Excel列宽样式策略类 import com.alibaba.excel.enums.CellDataTypeEnum; import com.alibaba.excel.metadata.Head; import com.alibaba.excel.metadata.data.WriteCellData; import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; import com.alibaba.e…...
半月内笔者暂不写时评文
今晨,笔者在刚恢复的《新浪微博》发布消息表态如下:“要开会了!今起,半月内笔者暂不写敏感时评文,不让自媒体网管感到压力,也是张驰有度、识时务者为俊杰之正常选择。野钓去也。” 截图:来源笔者…...
Python面试题:如何在 Python 中解析 XML 文件?
在 Python 中解析 XML 文件可以使用内置的 xml.etree.ElementTree 模块。以下是一个示例,展示了如何使用这个模块解析 XML 文件: 读取 XML 文件: import xml.etree.ElementTree as ET# 读取 XML 文件 tree ET.parse(example.xml) root tr…...
3033.修改矩阵
1.题目描述 给你一个下标从 0 开始、大小为 m x n 的整数矩阵 matrix ,新建一个下标从 0 开始、名为 answer 的矩阵。使 answer 与 matrix 相等,接着将其中每个值为 -1 的元素替换为所在列的 最大 元素。 返回矩阵 answer 。 示例 1: 输入&am…...
解决MCM功率电源模块EMC的关键
对MCM功率电源而言,由于其工作在几百kHz的高频开关状态,故易成为干扰源。电磁兼容性EMC(Electro Magnetic Compatibility),是指设备或系统在其电磁环境中符合要求运行并不对其环境中的任何设备产生无法忍受的电磁干扰的…...
在conda的环境中安装Jupyter及其他软件包
Pytorch版本、安装和检验 大多数软件包都是随Anaconda安装的,也可以根据需要手动安装一些其他软件包。 目录 创建虚拟环境 进入虚拟环境 安装Jupyter notebook 安装matplotlib 安装 pandas 创建虚拟环境 基于conda包的环境创建、激活、管理与删除http://t.cs…...
spark中的floor函数
在Spark中,floor函数是一种数学函数,用于返回不大于给定数值的最大整数。具体作用如下: 1. 数值操作: floor函数会将每个元素向下取整到最接近的整数。例如,对于浮点数或双精度数值,它会返回不大于该数值的…...
最简单的Docker离线安装教程
最简单的Docker离线安装教程 方式一 RPM 包方式1. 在线下载 RPM 包2. 将 RPM 包拷贝到安装机器3. 安装4. 启动 方式二 二进制安装方式(推荐)1. 下载包2. 将包进行解压授权3. 注册 systemd4. 自启和启动 一直以来在线安装 docker 到服务器上是非常方便的&…...
如何在 Python 中创建一个类似于 MS 计算器的 GUI 计算器
问题背景 假设我们需要创建一个类似于微软计算器的 GUI 计算器。这个计算器应该具有以下功能: 能够显示第一个输入的数字。当按下运算符时,输入框仍显示第一个数字。当按下第二个数字时,第一个数字被替换。 解决方案 为了解决这个问题&am…...
警惕:与ChatGPT共享业务数据可能十分危险
您已经在使用ChatGPT了吗?或者您正在考虑使用它来简化操作或改善客户服务?虽然ChatGPT提供了许多好处,但重要的是,您要意识到与ChatGPT这样的人工智能工具共享敏感业务数据相关的安全风险。下面,我们概述了一些关键问题…...
基于MacOS系统Sonoma 14.5的SSH服务禁止密码登录
基于系统Sonoma 14.5,不同系统有所差异。 修改sshd_config文件 sudo vim /etc/ssh/sshd_config找到以下两行取消注释,修改值为 no PasswordAuthentication no KbdInteractiveAuthentication no重启sshd服务 # 关闭服务 sudo launchctl unload -w /System…...
python打卡day49
知识点回顾: 通道注意力模块复习空间注意力模块CBAM的定义 作业:尝试对今天的模型检查参数数目,并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...
python如何将word的doc另存为docx
将 DOCX 文件另存为 DOCX 格式(Python 实现) 在 Python 中,你可以使用 python-docx 库来操作 Word 文档。不过需要注意的是,.doc 是旧的 Word 格式,而 .docx 是新的基于 XML 的格式。python-docx 只能处理 .docx 格式…...
【JavaSE】绘图与事件入门学习笔记
-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角,以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向,距离坐标原点x个像素;第二个是y坐标,表示当前位置为垂直方向,距离坐标原点y个像素。 坐标体系-像素 …...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
安宝特案例丨Vuzix AR智能眼镜集成专业软件,助力卢森堡医院药房转型,赢得辉瑞创新奖
在Vuzix M400 AR智能眼镜的助力下,卢森堡罗伯特舒曼医院(the Robert Schuman Hospitals, HRS)凭借在无菌制剂生产流程中引入增强现实技术(AR)创新项目,荣获了2024年6月7日由卢森堡医院药剂师协会࿰…...
基于Springboot+Vue的办公管理系统
角色: 管理员、员工 技术: 后端: SpringBoot, Vue2, MySQL, Mybatis-Plus 前端: Vue2, Element-UI, Axios, Echarts, Vue-Router 核心功能: 该办公管理系统是一个综合性的企业内部管理平台,旨在提升企业运营效率和员工管理水…...
stm32wle5 lpuart DMA数据不接收
配置波特率9600时,需要使用外部低速晶振...
LLaMA-Factory 微调 Qwen2-VL 进行人脸情感识别(二)
在上一篇文章中,我们详细介绍了如何使用LLaMA-Factory框架对Qwen2-VL大模型进行微调,以实现人脸情感识别的功能。本篇文章将聚焦于微调完成后,如何调用这个模型进行人脸情感识别的具体代码实现,包括详细的步骤和注释。 模型调用步骤 环境准备:确保安装了必要的Python库。…...
解析两阶段提交与三阶段提交的核心差异及MySQL实现方案
引言 在分布式系统的事务处理中,如何保障跨节点数据操作的一致性始终是核心挑战。经典的两阶段提交协议(2PC)通过准备阶段与提交阶段的协调机制,以同步决策模式确保事务原子性。其改进版本三阶段提交协议(3PC…...
Monorepo架构: Nx Cloud 扩展能力与缓存加速
借助 Nx Cloud 实现项目协同与加速构建 1 ) 缓存工作原理分析 在了解了本地缓存和远程缓存之后,我们来探究缓存是如何工作的。以计算文件的哈希串为例,若后续运行任务时文件哈希串未变,系统会直接使用对应的输出和制品文件。 2 …...
