【C++笔记】C++继承

【C++笔记】C++继承

  • 一、继承的概念
  • 二、继承的语法和权限
  • 三、父类和子类成员之间的关系
    • 3.1、子类赋值给父类(切片)
    • 3.2、同名成员
  • 四、子类中的默认成员函数
    • 4.1、构造函数
    • 4.2、拷贝构造
    • 4.3、析构函数
  • 五、C++继承大坑之“菱形继承”
    • 5.1、什么是“菱形继承”
    • 5.2、解决方法

一、继承的概念

继承:

继承是面向对象编程中的一个重要概念,它允许一个类(称为子类或派生类)继承另一个类(称为父类或基类)的属性和方法。继承是一种代码重用的方式,它可以减少代码的重复,提高代码的可维护性和可扩展性。
继承的基本原理是子类可以使用父类的属性和方法,而不需要重新编写代码。子类可以继承父类的公共属性和方法,也可以重写父类的方法或添加新的属性和方法。这种机制使得子类可以扩展父类的功能,同时保留父类的特性。

用一个简单的例子演示一下:
在这里插入图片描述
这里B继承了A,B不仅可以访问自己的成员变量,也可以访问自己父类的成员变量和成员函数。

二、继承的语法和权限

继承的语法格式如下:

class 子类名字:继承方式 父类名字{};

子类继承父类的继承方法有三种:

public
protected
private

(protected修饰的成员在内里边可以使用,在类外边不可以使用)
不同的修饰方法会使得子类中的父类成员权限不同,而且父类中以不同权限修饰符修饰的成员在继承到子类后的权限也会不同。
比如最简单的以public的方式继承:
在这里插入图片描述
public继承方式可以访问到父类中public的成员。
而如果是父类中的private成员就不行了:
在这里插入图片描述

还有其他的组合如下表:
在这里插入图片描述
有人可能会觉得这张表好复杂,觉得要背下来的话一定很困难。
其实我们并不需要去背这张表,我们仔细观察这张表之后就会发现其中的规律。
因为最后一个行都是不可见,我们可以把最后一行特殊化处理,然后剩下的我们仔细观察后就会发现,表中的任何一个结果都可以总结为:

min(父类中的修饰符,子类的继承方式)
在这里插入图片描述

三、父类和子类成员之间的关系

3.1、子类赋值给父类(切片)

因为子类继承了父类的成员,所以子类也可以看作是一种特殊的父类。那么将子类对象赋值给父类对象会怎么样呢?
在这里插入图片描述
我们发现父类自己的成员还是可以正常访问的,可若要是想访问子类的成员就不行了:
在这里插入图片描述
这样想跟我们平时理解的赋值不一样啊。

其实它在底层执行了一个“切片”操作:
在这里插入图片描述

因为父类中没有_id,所以父类并不会接收子类的_id,父类之后接受自己有的成员的值。
所以子类自己独有的成员也就被“切”掉了。

其他的赋值方式例如引用:
在这里插入图片描述
引用我们可以理解为,父类的引用只引用了子类中属于父类的那一部分。

指针:
在这里插入图片描述
指针其实是并不存在“切片”操作的,只需要执行子类的首地址即可,因为这是Person类型的指针,而指针能访问到的范围其实是由指针类型已经决定了的。
所以父类的指针只会访问到子类中属于父类的成员。

3.2、同名成员

同名成员变量:

有时候父类和之类中会存在一些同名成员变量,比如name:
在这里插入图片描述
这时候编译器会议子类的成员优先。
如果真要想访问到父类的就得要加上域作用限定符,限定为访问父类的:
在这里插入图片描述
同名成员函数:
如果父类和子类之中存在同名函数又会怎么样呢?
在这里插入图片描述
这其实就构成了“隐藏”,并不是函数重载,函数重载一定要是在同一作用域,而两个类之间并不是同一个作用域,即使他们之间是继承关系。
隐藏的条件是只需要函数名相同,对参数列表和返回值都没有要求。
这时候编译器还是会优先选择子类的函数,这也称之为父类的函数被子类的函数隐藏了。
这时候如果想要调用父类的,也需要加上域作用限定符:
在这里插入图片描述

四、子类中的默认成员函数

4.1、构造函数

我们来看看,继承关系中的构造函数会怎么做:
在这里插入图片描述

如果创建一个子类对象,编译器会先调父类的构造函数再调用子类的构造函数。

这其实是编译器自动调用的,即使我们没有显示的写出子类的构造函数,编译器也会自动去调用父类的构造函数:
在这里插入图片描述

而如果我们想要在子类中显示的构造父类对象,就必须将父类对象当成一个整体(当成一个对象)去构造,即调用父类的构造函数:
在这里插入图片描述
记住一定要在初始化列表处调用,不然就会存在父类构造被调用两次的问题:
在这里插入图片描述
这是因为编译器默认就会在初始化列表中调用父类构造函数。

而我们不能想当然的像下面这样初始化父类:
在这里插入图片描述
这是规定!

4.2、拷贝构造

拷贝构造也是要先调用父类的再调用子类的:
在这里插入图片描述
再构造函数中我们可以直接将子类对象传递给父类的构造函数,因为父类会通过“切片”操作拿到子类中父类的部分。

4.3、析构函数

析构函数和构造函数正好相反,析构要求的是先调用子类的析构再调用父类的析构。
在这里插入图片描述
而如果我们在子类的构造函数中显示的调用父类的构造函数就会发生调两次析构的危险:
在这里插入图片描述
而析构函数调用两次是很危险的,这很有可能就会导致同样的资源被释放两次的错误。

其实这是因为父类的析构函数是编译器自动调用且是在子类析构结束后才调用的,所以也就决定了它不能像构造函数一样写在初始化列表里。
也就不能自己调用,只能由编译器调用。

五、C++继承大坑之“菱形继承”

因为C++时出现的比较早的面向对象的语言,也就没有多少其他的面向对象语言可以参考,所以许多面向对象的“坑”也就避免不了了。
其中一个坑就是今天要讲的“菱形继承”。

5.1、什么是“菱形继承”

C++是支持多继承的,也就是一个类可能会存在多个直接父类,例如下面这个例子:
在这里插入图片描述
他们之间的继承关系如下图所示:
在这里插入图片描述
而如果这些关系再复杂一点儿,就会变成“菱形继承”了:
在这里插入图片描述
在这里插入图片描述
在这样的继承状态中,处于中间的A、B两个类是没有什么问题的,问题就出在最下面的C这个类:
在这里插入图片描述
从代码中我们并不能看出问题出在哪里,我们得到监视窗口中才能看出:
在这里插入图片描述
从内存中我们可以看到c1中竟然存了两个_o(一个是A继承的,一个是B继承的),这也就是为什么报错提示访问不明确的原因。

5.2、解决方法

方法一:加类域修饰
既然两个_o一个是A继承的,一个是B继承的,那我们直接指定是哪个类的不就行了:
在这里插入图片描述

方法二:virtual虚继承
还有一种方法就是在菱形继承的“腰部”加上virtual继承:
在这里插入图片描述
简单来说就是将菱形继承中具有公共父类和公共子类的那几个类继承其公共父类的方式全都改成虚继承。

虽然说菱形继承的问题已经被解决了,但是我们最好还是不要弄出菱形继承的好,多继承是没什么问题的,但是菱形继承就是个大坑。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++深度优化(DFS)算法的应用:收集所有金币可获得的最大积分

涉及知识点 深度优化(DFS) 记忆化 题目 节点 0 处现有一棵由 n 个节点组成的无向树,节点编号从 0 到 n - 1 。给你一个长度为 n - 1 的二维 整数 数组 edges ,其中 edges[i] [ai, bi] 表示在树上的节点 ai 和 bi 之间存在一条边。另给你一个下标从 0…

ArcGIS笔记13_利用ArcGIS制作岸线与水深地形数据?建立水动力模型之前的数据收集与处理?

本文目录 前言Step 1 岸线数据Step 2 水深地形数据Step 3 其他数据及资料 前言 在利用MIKE建立水动力模型(详见【MIKE水动力笔记】系列)之前,需要收集、处理和制作诸多数据和资料,主要有岸线数据、水深地形数据、开边界潮位驱动数…

位(bit)、字节(byte)、字、英文字符、中文字符的关系详解(涵盖字符编码)

目录 0 引言1 位、字节、字2 字符编码2.1 为什么要有字符编码2.2 字符编码的种类有哪些拓展:ANSI 编码 3 英文字符与中文字符的区别 🙋‍♂️ 作者:海码007📜 专栏:C专栏💥 标题:位(…

至高直降3000元,微星笔记本双11爆款推荐、好评有礼拿到手软

今年双11来的更早一些,微星笔记本先行的第一波雷影17促销活动,就已经领略到玩家们满满的热情。开门红高潮一触即发,微星笔记本双11活动周期至高直降3000元,众多爆款好货已经开启预约预售:有硬核玩家偏爱的性能双雄&…

聚观早报 |2024款飞凡R7官宣;小米14新配色材质

【聚观365】10月27日消息 2024款飞凡R7官宣 小米14新配色材质 金山办公2023第三季度业绩 IBM2023第三季度业绩 新东方2024财年第一季度业绩 2024款飞凡R7官宣 飞凡汽车官宣,2024款飞凡R7将于11月上市,新车将搭载飞凡巴赫座舱,同时超过1…

Node编写重置用户密码接口

目录 前言 定义路由和处理函数 验证表单数据 实现重置密码功能 前言 接前面文章,本文介绍如何编写重置用户密码接口 定义路由和处理函数 路由 // 重置密码的路由 router.post(/updatepwd, userinfo_handler.updatePassword) 处理函数 exports.updatePasswo…

php之 角色的权限管理(RBAC)详解

RBAC(Role-based access control)是一种常见的权限管理模型,通过将用户分配至特定的角色,以及为角色分配访问权限,实现了权限管理的目的。以下是关于RBAC的详细解释: 角色:RBAC模型的核心是角色…

65、内网安全-域环境工作组局域网探针方案

目录 案例1-基本信息收集操作演示案例2-网络信息收集操作演示案例3-用户信息收集操作演示案例4-凭据信息收集操作演示案例5-探针主机域控架构服务操作演示涉及资源 我们攻击内网一般是借助web攻击,直接进去,然后再去攻击内网,那么攻击的对象一…

搞懂 MySql 的架构和执行流程

搞懂 MySql 的架构和执行流程 1、MySQL 的三层架构2、SQL 的执行流程2.1、连接器2.2、解析器2.3、预处理器2.4、优化器2.5、执行器2.6、存储引擎 3、关于Select 的两个顺序 1、MySQL 的三层架构 MySQL的三层结构包括: 连接层:负责与MySQL客户端之间的通…

matlab中类的分别之handle类和value类——matlab无法修改类属性值的可能原因

写在之前(吐槽) 最近由于变化了一些工作方向,开始需要使用matlab进行开发,哎哟喂,matlab使用的我想吐,那个matlab编辑器又没代码提示,又没彩色,我只好用vscode进行代码编辑&#xf…

13.6性能测试理论

一.什么是性能测试 1.定义: 测试人员借助性能测试工具(LoadRunner等),模拟系统在不同场景下(使用高峰期等),对应的性能指标是否达到预期. 2.性能测试和功能测试的区别: a.功能测试依靠人工,性能测试依靠工具. b)功能测试要求软件能正常运行,不管什么场景,性能测试要求软件…

嵌入式 Tomcat 调校

SpringBoot 嵌入了 Web 容器如 Tomcat/Jetty/Undertow,——这是怎么做到的?我们以 Tomcat 为例子,尝试调用嵌入式 Tomcat。 调用嵌入式 Tomcat,如果按照默认去启动,一个 main 函数就可以了。 简单的例子 下面是启动…

故障诊断入门书籍资料免费领取

前言 本期分享免费提供9本故障诊断领域相关的书籍资料,可自行下载 一、主要内容 二、书籍获取

VR结合|山海鲸虚拟展厅解决方案

方案背景 虚拟现实技术是另一项革命性的创新,它可以将用户带入一个完全虚拟的环境中。借助VR头盔和控制器,用户可以亲临虚拟现实中,与数字世界互动,仿佛置身于其中。 山海鲸根据用户实际需求变化将数字孪生与虚拟现实技术相结合…

Web攻防06_sqlmap的使用

文章目录 参考链接: SQLMAP简介支持五种不同的注入模式 数据猜解-库表列数据权限操作引出权限:引出文件:引出命令(执行命令): 提交方法-POST&HEAD&JSONPost注入cookie注入注入请求头中(…

【1++的Linux】之进程间通信

👍作者主页:进击的1 🤩 专栏链接:【1的Linux】 文章目录 一,进程间通信的目的二,管道 一,进程间通信的目的 数据传输:一个进程需要将它的数据发送给另一个进程资源共享:…

深度学习:张量 介绍

张量[1]是向量和矩阵到 n 维的推广。了解它们如何相互作用是机器学习的基础。 简介 虽然张量看起来是复杂的对象,但它们可以理解为向量和矩阵的集合。理解向量和矩阵对于理解张量至关重要。 向量是元素的一维列表: 矩阵是向量的二维列表: 下标…

unity button移动位置some values driven by canvas

1 可以在button父节点把限制取消勾选 2 在不动整个布局的情况下,只修改局部变量:忽略布局即可

【C++】list的介绍及使用 | 模拟实现list(万字详解)

目录 一、list的介绍及使用 什么是list? list的基本操作 增删查改 获取list元素 不常见操作的使用说明 ​编辑 接合splice ​编辑 移除remove 去重unique 二、模拟实现list 大框架 构造函数 尾插push_back 迭代器__list_iterator list的迭代器要如何…

2023年MathorCup高校数学建模挑战赛大数据挑战赛赛题浅析

比赛时长为期7天的妈杯大数据挑战赛如期开赛,为了帮助大家更好的选题,首先给大家带来赛题浅析,为了方便大家更好的选题。 赛道 A:基于计算机视觉的坑洼道路检测和识别 A题,图像处理类题目。这种题目的难度数模独一档…