【C++】继承详解
本篇要分享的内容是关于继承的内容哼哼哼啊啊啊啊啊啊啊啊啊啊啊啊啊啊
以下为本篇目录
目录
1.简单了解继承
2.继承的简单定义
3.继承简单使用
4.继承方式
4.1基类的privat
4.2基类的protected
4.3不可见与private的区别
5.父子类对象赋值转换
6.继承的作用域
7.子类 / 派生类的默认成员函数
7.1默认构造
7.2拷贝构造
7.3析构函数及其原因
首先封装、继承、多态是面向对象的三大特性,本篇先了解继承。
继承(inheritance)机制是一个一个一个面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行扩展,增加功能,这样产生新的类,称派生类。
简单来说继承就是可以将代码的内容进行复用
比如我们在学习冒泡排序、堆排序、快速排序这些排序需要对数据进行交换,那么使用交换数据的功能就属于函数集的复用,也就是将公共集的部分抽取出来被调用,这就是之前我们学到的复用。
1.简单了解继承
下面使用代码简单认识继承


可以看到这里定义了两个类,一个学生类一个教师类,我们发现有些数据是两个类中共有的,那么我们就可以单独将这些属性单独领出来,重新创建一个类来使用。
class Person
{string _name;string _id;string _tel;int age;
};

根据上图,具有两个类公共部分的叫做父类,或者基类;在图的下方的两个类就叫做子类,或者派生类;
2.继承的简单定义

我们可以先暂时记住这种继承方法,下文还会详细介绍
3.继承简单使用
用代码简单演示一下继承的使用
class Person
{
public:void Print(){cout << "name:" << _name << endl;cout << "age:" << _age << endl;}protected:string _name = "peter"; // 姓名int _age = 18;
};class Student : public Person
{
protected:int _stuid; // 学号
};class Teacher : public Person
{
protected:int _jobid; // 工号
};
int main()
{Student s;Teacher t;return 0;
}
可以看到如上代码定义了三个类,一个是Person类,还有Student类和Teacher类,并且两个子类中都有自己特有的的元素,学号和工号,在这样的情况下继承了父类并各自创建对象,那这个对象的属性都有什么呢?

通过调试后的监视窗口我们可以看到在使用继承之后,子类创建的对象都具有父类的属性。
同样的也可以继承成员函数
可以看到即使在子类中没有定义函数,在继承了父类之后,子类的对象也可以调用父类中的函数。
4.继承方式
在上面的代码中呢我们会看到一些关键字,比如protected,并且会有疑问那继承方式只能是public吗,接下来我们回到继承的定义

同时也要和之前类和对象中的封装的内容联系起来

我们在之前的封装中谈到过protected(保护)和private(私有),也说过保护和私有没有什么区别, 保护和私有在类的外部都不能访问,共有的在类外和类里面都能访问。

现在我们所接触到的继承中也有三种继承方式。但是这里需要理解的是,在父类中设置访问权限后,继承到子类中是否还设置了同样的权限呢?所以如下表

这个表来表示父类的成员在子类中又怎样的访问关系。
这个表的内容是很重要的,在记忆是要讲究技巧
首先我们可以将父类和子类想象成为父亲和儿子,父亲的私房钱是无论如何都不可以被儿子所知的,所以儿子不可以拿到父亲的私房钱;
我们使用最开始的代码演示
4.1基类的privat

可以看到在父类中将打印函数设为私有,子类对象便不能访问;

同样的不仅是在类的外部,在子类的内部同样不能访问,爸爸的私房钱是不能动的;
4.2基类的protected
在之前的封装中protected和private是没有区别的,但是在继承中两个方式便有了区别

还是上列代码,我们将Print保护起来,在类的外部显然是不能调用的

但是在子类的内部却能被调用;
所以protected在继承中才能体现出它的价值。
当我们通过两个例子之后就会发现继承方式会取在类的基类访问限定符和继承方式中权限小的那一个
所以再次观察这个表格你会发现两者相交权限会取小的限定符进行访问,这就是记忆的技巧,了解他的规律即可。
最后还需要注意的是我们都知道class类在不写继承方式的情况下默认是私有继承
可以看到Student继承父类没有写继承方式,默认为私有继承
但是struct类在不写继承方式的情况下默认为共有继承

可以看到运行成功
但是在这里我希望大家在使用继承时最好最好将继承方式规范写完整。
4.3不可见与private的区别
在上述的表格中我们看到了这两个信息

他们的本质区别就在于:私有属性是类里和类外都不可用,如同父亲的私房钱,怎么样都看不见用不到;
不可见属性是类里可以使用,但是类外不可使用;如同结婚时的彩礼,只能结婚时用,其他时间不能使用;
区别就这么简单。
5.父子类对象赋值转换
我们知道不同类型之间的对象赋值的时候,如果是相近类型会发生隐式类型转换,发生隐式类型转换就会产生中间变量

比如这里d时double类型,double和int类型相似,都是用来记录数据的类型所以可以发生隐式类型转换,但是转化时会产生中间变量,

在这里可以看到使用引用会报错,原因是因为这里的r引用的是隐式转换的中间变量,但是中间变量具有常性,所以需要加const才能完成转换;

那类和对象之间的转化是怎样的呢?

我们使用学生和教师类创建对象,可以看到两个相似的类同样可以发生隐式类型转换。
但是当我们使用引用的时

我们发现这里并没有产生临时对象。
那是不是内置类型隐式转换会产生临时对象,而自定义类型隐式转换不会发生隐式转换呢?
如下例

可以看到还是产生了临时对象

同样需要加上从const;
所以这里有一个结论:public继承时,父类和子类是一个is-a的关系,相当于召唤出替身,
子类的对象赋值给父类的对象、或者父类指针、或者父类引用,我们认为是天然的,中间不产生临时对象,也被称作父子类的赋值兼容规则,也叫做切片。
那is-a是什么关系呢?简单说就是:你有的,我都有
观察下图

当子类继承了父类之后,子类创建的对象可以看作是一个一个一个父类的对象,也就可以直接赋值给父类不会产生中间变量。

那这一小串代码就如下图

6.继承的作用域
父类和子类是有独立的作用域的,所以可以分别再父类和子类中定义相同的变量

虽然子类继承了父类的属性和函数,但是两者的作用域不同。那么有以下问题
class Person
{
protected:string _name = "wdd";int _num = 111;};
class Student : public Person
{
public:void Print(){cout << " 姓名:" << _name << endl;cout << " 身份证号:" << Person::_num << endl;cout << " 学号:" << _num << endl;}
protected:int _num = 999; // 学号
};
在子类定义的打印函数中能否访问到_num?如果能访问,访问的又是谁的_num呢?
测试如下

可以看到_num访问的是Student中的属性;
和我们之前讲到的就近原则同理 。
那我们想要在子类中访问父类的属性加上作用域和访问限定符即可

可以看到还是在子类中,可以通过指定的作用域来访问父类中的属性 。
根据以上来看,我们得出结论:父类和子类可以有同名成员,因为他们是独立作用域;默认情况是直接访问子类的,子类同名成员会隐藏父类同名成员。
同样的成员函数也是如此
class A
{
public:void fun(){cout << "func()" << endl;}
};
class B : public A
{
public:void fun(int i){A::fun();cout << "func(int i)->" << i << endl;}
};
如上代码中两个func函数不是函数重载,而是函数隐藏。
之前我们说过函数重载是在同一个作用域中,函数名相同,函数的参数不同才能构成函数重载,但是如上代码中两个函数的作用域不同

可以看到我们使用B类创建了对象,并且使用其调用fun函数,调用的是B类中的fun函数;
但是我们想要去调用父类的fun函数会出现错误

可以看到它的错误为函数中的参数太少,因为父类的函数是无参的,并且与子类中的函数同名,于是便对父类中的fun函数进行了隐藏;
7.子类 / 派生类的默认成员函数
7.1默认构造
我们之前在构造函数中说过在类中不写构造函数,编译器会默认生成构造函数,在我们写了构造函数便不会生成构造函数,如此观察以下代码和运行结果

可以看到的是1.我们使用子类继承了一个父类2.使用子类创建了一个对象3.在子类中定义任何的构造函数和析构函数4.输出的结果中出现了父类的构造和析构函数
这里的原因是因为这里子类(Student)是有两部分构成的,一部分是子类本身的结构,另一部分是继承了父类的结构,接下来观察父类的构造函数和析构函数
父类内容如下
class Person
{
public:Person(const char* name = "peter"): _name(name){cout << "Person()" << endl;}Person(const Person& p): _name(p._name){cout << "Person(const Person& p)" << endl;}Person& operator=(const Person& p){cout << "Person operator=(const Person& p)" << endl;if (this != &p)_name = p._name;return *this;}~Person(){cout << "~Person()" << endl;}
protected:string _name; // 姓名
};
可以看到的是我们在父类中定义了构造函数和析构函数;
那么接下来我们在子类中写一个构造函数,观察它在创建对象时是否会使用自己的构造函数

可以看到在子类中写了构造函数之后s对象也调用了自家的构造函数。
这里需要注意的是需要初始化父类的内容时需要声明父类中的初始化内容,要将父类的内容当成一个完整的对象去初始化,而不是单个的使用初始化(与之前的匿名对象有些相似)![]()
7.2拷贝构造
复用上面的代码我们观察拷贝构造

使用s1拷贝构造了s2,运行的结果可以看到还是会优先调父类的拷贝构造![]()
我们可以继续在子类中定义拷贝构造的函数
可以看到这里又在子类中定义了拷贝构造函数,在输出的结果中又多了一行![]()
这就是子类调用了自己的拷贝构造函数。
7.3析构函数及其原因
和构造函数相同,自己定义之后编译器就不会默认生成,没有自己定义编译器就会默认成生成,在上面的代码中可以看到运行的结果一直在调用父类的析构函数,析构函数同样可以自己定义

可以看到在最下方我们想要使用复用父类的析构函数却发现析构函数被调用了两次,
这是因为编译器对构造和析构是有顺序的;
我们之前都了解过构造和析构的顺序
构造的顺序是先父后子
析构的顺序是先子后父
这也是为什么上面写的子类的析构函数可以调用父类的成员函数。
简单来说如同没有你的父母就没有你
如果析构函数的顺序是先父后子的话,可能会将父类的数据空间释放调,如果子类需要用到父类的数据时父类已经先被析构,再访问父类数据会有风险。
所以为了保证析构安全,要先子后父
父类析构函数不需要显式调用,子类析构函数结束时会自动调用父类析构函数。
以上就是关于继承的基础内容,如果对你有所帮助还请三连支持,感谢您的阅读。
相关文章:
【C++】继承详解
本篇要分享的内容是关于继承的内容哼哼哼啊啊啊啊啊啊啊啊啊啊啊啊啊啊 以下为本篇目录 目录 1.简单了解继承 2.继承的简单定义 3.继承简单使用 4.继承方式 4.1基类的privat 4.2基类的protected 4.3不可见与private的区别 5.父子类对象赋值转换 6.继承的作用域 7.子…...
react:swr接口缓存
useSWR 是一个 React Hooks,是 HTTP 缓存库 SWR 的核心方法之一。SWR 是一个轻量级的 React Hooks 库,通过自动缓存数据来实现 React 的数据获取。 第一个参数是被缓存的数据的 key, 第二个参数是一个函数,该函数返回数据或者一个…...
2023-11 | 短视频批量下载/爬取某个用户的所有视频 | Python
这里以鞠婧祎的个人主页为demo https://www.douyin.com/user/MS4wLjABAAAACV5Em110SiusElwKlIpUd-MRSi8rBYyg0NfpPrqZmykHY8wLPQ8O4pv3wPL6A-oz 【2023-11-4 23:02:52 星期六】可能后面随着XX的调整, 方法不再适用, 请注意 找到接口 找到https://www.douyin.com/aweme/v1/web/…...
【JAVA学习笔记】66 - 本章作业(IO流)
项目代码 https://github.com/yinhai1114/Java_Learning_Code/tree/main/IDEA_Chapter19/src/com/yinhai/homework 1.使用File类和FileWriter类 (1)在判断e盘下是否有文件夹mytemp,如果没有就创建mytemp public class Homework01 {public static void main(String…...
vscode中 vue3+ts 项目的提示失效,volar插件失效问题解决方案
文章目录 前情提要bug回顾解决方案最后 前情提要 说起来很耻辱,从mac环境换到window环境,vscode的配置都是云端更新过来的,应该是一切正常才对,奇怪的是我的项目环境出现问题了,关于组件的ts和追踪都没有效果ÿ…...
Elasticsearch:在 ES|QL 中使用 DISSECT 和 GROK 进行数据处理
目录 DISSECT 还是 GROK? 或者两者兼而有之? 使用 DISSECT 处理数据 Dissect pattern 术语 例子 DISSECT 关键修饰符 右填充修饰符 (->) 附加修饰符 () 添加顺序修饰符( 和 /n) 命名的跳过键(?…...
基于自适应自回归模型的高级人工智能概念及其实现
基于自适应自回归模型的高级人工智能概念及其实现 摘要:一、引言:二、方法:三、讨论:四、结论:草稿实现计算摘要: 在人工智能研究领域中,预测未来的信息往往会遇到信息不明确的问题,尤其是在自回归模型中,这一问题尤为突出。本研究提出一个新颖的假设,将能自主解决信…...
windows的mysql启动错误,查看windows日志
1、点击左下角开始按钮,计算机上右键,点击【管理】。 2、在计算机管理界面依次找到【系统工具】,选择【时间查看器】,打开【windows日志】,点击【应用程序】 3、在右侧找到,最新的mysql错误信息。双击查看。…...
centos7部署Canal与Canal集成使用
1、简介 canal [kə’nl],译意为水道/管道/沟渠,主要用途是基于 MySQL 数据库增量日志解析,提供增量数据订阅和消费 早期阿里巴巴因为杭州和美国双机房部署,存在跨机房同步的业务需求,实现方式主要是基于业务 trigge…...
C语言--分段函数--switch语句
如何用switch语句写分段函数呢?⭐️ 首先介绍一下switch语句的语法规则⭐️ switch(整形表达式) {case 常量表达式1; //标签必须唯一语句块1;break;case 常量表达式2; //if(a0),而case中时系统自动加语句块2;break;c…...
动态规划31(Leetcode188买卖股票的最佳时机4)
代码: 我的状态方程: buy[i][j]max{buy[i−1][j],sell[i−1][j-1]−price[i]} 题解里的: buy[i][j]max{buy[i−1][j],sell[i−1][j]−price[i]} ..没理解题解的 但我的通过了 class Solution {public int maxProfit(int k, int[] pric…...
npm包管理相关命令
前置条件,准备npm账号,并登录,npm login 或者 npm adduser (这一行同样需要输入账号密码登录,之后就不用登录了) 验证是否登录:npm whoami 还可以查看用户简介:npm profile get …...
2023年Q3乳品行业数据分析(乳品市场未来发展趋势)
随着人们生活水平的不断提高以及对健康生活的追求不断增强,牛奶作为优质蛋白和钙的补充品,市场需求逐年增加。 今年Q3,牛奶乳品市场仍呈增长趋势。根据鲸参谋电商数据分析平台的相关数据显示,2023年7月-9月,牛奶乳品市…...
软考 系统架构设计师系列知识点之边缘计算(2)
接前一篇文章:软考 系统架构设计师系列知识点之边缘计算(1) 所属章节: 第11章. 未来信息综合技术 第4节. 边缘计算概述 3. 边缘计算的特点 边缘计算是在靠近物或数据源头的网络边缘侧,融合网络、计算、存储、应用核心…...
Maven中的继承与聚合
一,继承 前面我们将项目拆分成各个小模块,但是每个小模块中有很多相同的依赖于是我们创建一个父工程将模块中相同的依赖定义在父工程中,然后子工程继承父工程Maven作用:简化依赖配置,统一依赖管理,可以实现多重继承像J…...
第三章 UI开发的点点滴滴
一、常用控件的使用方法 1.TextView android:gravity"center" 可选值:top、bottom、left、right、center等,可以用"|"来同时指定多个值,center表示文字在垂直和水平方向都居中 android:textSize 指定文字的大小&#…...
637. 二叉树的层平均值
描述 : 给定一个非空二叉树的根节点 root , 以数组的形式返回每一层节点的平均值。与实际答案相差 10-5 以内的答案可以被接受。 题目 : 637. 二叉树的层平均值 分析 : 这个题和前面的几个一样,只不过是每层都先将元素保存下来,最后求平均就行了: 解…...
【Java笔试强训】Day9(CM72 另类加法、HJ91 走方格的方案数)
CM72 另类加法 链接:另类加法 题目: 给定两个int A和B。编写一个函数返回AB的值,但不得使用或其他算数运算符。 题目分析: 代码实现: package Day9;public class Day9_1 {public int addAB(int A, int B) {// wr…...
django REST框架- Django-ninja
Django 是我学习的最早的web框架,大概在2014年,当时选他原因也很简单就是网上资料比较丰富,自然是遇到问题更容易找答案,直到 2018年真正开始拿django做项目,才对他有了更全面的了解。他是一个入门有门槛,学…...
数据结构与算法C语言版学习笔记(3)-线性表的链式结构:链表
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言:回顾顺序表的优缺点:为什么要引入链式结构的线性表? 一、什么是链表?二、链表的分类①为什么要设置头节点&…...
DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径
目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...
2024年赣州旅游投资集团社会招聘笔试真
2024年赣州旅游投资集团社会招聘笔试真 题 ( 满 分 1 0 0 分 时 间 1 2 0 分 钟 ) 一、单选题(每题只有一个正确答案,答错、不答或多答均不得分) 1.纪要的特点不包括()。 A.概括重点 B.指导传达 C. 客观纪实 D.有言必录 【答案】: D 2.1864年,()预言了电磁波的存在,并指出…...
Vue2 第一节_Vue2上手_插值表达式{{}}_访问数据和修改数据_Vue开发者工具
文章目录 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染2. 插值表达式{{}}3. 访问数据和修改数据4. vue响应式5. Vue开发者工具--方便调试 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染 准备容器引包创建Vue实例 new Vue()指定配置项 ->渲染数据 准备一个容器,例如: …...
Cloudflare 从 Nginx 到 Pingora:性能、效率与安全的全面升级
在互联网的快速发展中,高性能、高效率和高安全性的网络服务成为了各大互联网基础设施提供商的核心追求。Cloudflare 作为全球领先的互联网安全和基础设施公司,近期做出了一个重大技术决策:弃用长期使用的 Nginx,转而采用其内部开发…...
2025盘古石杯决赛【手机取证】
前言 第三届盘古石杯国际电子数据取证大赛决赛 最后一题没有解出来,实在找不到,希望有大佬教一下我。 还有就会议时间,我感觉不是图片时间,因为在电脑看到是其他时间用老会议系统开的会。 手机取证 1、分析鸿蒙手机检材&#x…...
Linux --进程控制
本文从以下五个方面来初步认识进程控制: 目录 进程创建 进程终止 进程等待 进程替换 模拟实现一个微型shell 进程创建 在Linux系统中我们可以在一个进程使用系统调用fork()来创建子进程,创建出来的进程就是子进程,原来的进程为父进程。…...
处理vxe-table 表尾数据是单独一个接口,表格tableData数据更新后,需要点击两下,表尾才是正确的
修改bug思路: 分别把 tabledata 和 表尾相关数据 console.log() 发现 更新数据先后顺序不对 settimeout延迟查询表格接口 ——测试可行 升级↑:async await 等接口返回后再开始下一个接口查询 ________________________________________________________…...
腾讯云V3签名
想要接入腾讯云的Api,必然先按其文档计算出所要求的签名。 之前也调用过腾讯云的接口,但总是卡在签名这一步,最后放弃选择SDK,这次终于自己代码实现。 可能腾讯云翻新了接口文档,现在阅读起来,清晰了很多&…...
数学建模-滑翔伞伞翼面积的设计,运动状态计算和优化 !
我们考虑滑翔伞的伞翼面积设计问题以及运动状态描述。滑翔伞的性能主要取决于伞翼面积、气动特性以及飞行员的重量。我们的目标是建立数学模型来描述滑翔伞的运动状态,并优化伞翼面积的设计。 一、问题分析 滑翔伞在飞行过程中受到重力、升力和阻力的作用。升力和阻力与伞翼面…...
Vue 模板语句的数据来源
🧩 Vue 模板语句的数据来源:全方位解析 Vue 模板(<template> 部分)中的表达式、指令绑定(如 v-bind, v-on)和插值({{ }})都在一个特定的作用域内求值。这个作用域由当前 组件…...
