【C++】三大特性之继承

1 继承的概念及定义

1.1 继承的概念

继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行扩展、增加功能,这样产生新的类,称派生类(或子类)。而被继承的类称基类(或父类)。

继承呈现了面向对象程序设计的层次结构,体现了由简单到复杂的认知过程。以前我们接触的复用都是函数复用,继承是类设计层次的复用。

为什么需要有继承这个概念呢?

假设这样一个场景:在一个大学里,有本科生和研究生两种学生。无论是本科生还是研究生都有一些相似的特征,如他们都有名字、学号,都有电话等一系列共同的特征。而对于研究生而言,还有导师之类的独特特征。为了提高效率,减少代码冗余,我们可以将名字,学号等公用信息封装到一个类里面供本科生和研究生使用,而对于研究生,就可以在上述类的基础上进行继承,并新增导师信息等,得到研究生类。

	class Person{public:void Print(){cout << "name:" << _name << endl;cout << "age:" << _age << endl;}protected:string _name = "peter"; // 姓名int _age = 18;			// 年龄};// 继承后父类的Person的成员(成员函数+成员变量)都会变成子类的一部分。class Student : public Person{protected:int _stuid; // 学号};class Teacher : public Person{protected:int _jobid; // 工号};

1.2 继承定义

继承的格式

class 新类的名字:继承方式 继承类的名字{};

如上述的class Teacher : public Person

#include <iostream>
using namespace std;
int main()
{return 0;
}

![[Pasted image 20240308210117.png]]

类成员/继承方式public继承protected继承private继承
基类的public成员派生类的public成员派生类的protected成员派生类的private成员
基类的protected成员派生类的protected成员派生类的protected成员派生类的private成员
基类的private成员在派生类中不可见在派生类中不可见在派生类中不可见

总结:

  1. 基类private成员在派生类中无论以什么方式继承都是不可见的。这里的不可见是指基类的私有成员还是被继承到了派生类对象中,但是语法上限制派生类对象不管在类里面还是类外面都不能去访问它。
  2. 基类private成员在派生类中是不能被访问,如果基类成员不想在类外直接被访问,但需要在派生类中能访问,就定义为protected。可以看出保护成员限定符是因继承才出现的。
  3. 实际上面的表格我们进行一下总结会发现,基类的私有成员在子类都是不可见。基类的其他成员在子类的访问方式 == Min(成员在基类的访问限定符,继承方式),public > protected > private。
  4. 使用关键字class时默认的继承方式是private,使用struct时默认的继承方式是public,不过最好显示的写出继承方式。
  5. 在实际运用中一般使用都是public继承,几乎很少使用protetced/private继承,也不提倡使用protetced/private继承,因为protetced/private继承下来的成员都只能在派生类的类里面使用,实际中扩展维护性不强。

创建一个不能被继承的类
方式1:将父类的构造函数私有,此时子类无法调用父类构造函数因此子类对象无法实例化
方式2:c++11新增,final修饰的类为__最终类__,无法被继承 #final

class A final
{
.......
};

2 基类和派生类对象赋值兼容转换

  • 派生类对象 可以赋值给 基类的对象 / 基类的指针 / 基类的引用。这里有个形象的说法叫切片或者切割。寓意把派生类中父类那部分切来赋值过去。

  • 基类对象不能赋值给派生类对象。

  • 基类的指针或者引用可以通过强制类型转换赋值给派生类的指针或者引用。但是必须是基类的指针是指向派生类对象时才是安全的。这里基类如果是多态类型,可以使用RTTI(RunTime Type Information)的dynamic_cast 来进行识别后进行安全转换。

转化是自下而上的,也就是子类向父类转换


3 继承中的作用域

  1. 在继承体系中基类和派生类都有独立的作用域。
  2. 子类和父类中有同名成员,子类成员将屏蔽父类对同名成员的直接访问,这种情况叫隐藏,也叫重定义。(在子类成员函数中,可以使用 基类::基类成员 显示访问)

隐藏::子类会隐藏父类同名成员
函数名相同就构成隐藏 (返回值和参数可以不相同)
隐藏的原因:编译器会先在子类里面寻找相应成员,找不到才会去父类寻找。如果名称相同,在子类就找到了,不会进入父类

  1. 需要注意的是如果是成员函数的隐藏,只需要函数名相同就构成隐藏。
  2. 注意在实际中在继承体系里面最好不要定义同名的成员。

4 派生类的默认成员函数

  1. 派生类的构造函数必须调用基类的构造函数初始化基类的那一部分成员。如果基类没有默认的构造函数,则必须在派生类构造函数的初始化列表阶段显示调用。
  2. 派生类的拷贝构造函数必须调用基类的拷贝构造完成基类的拷贝初始化。
  3. 派生类的operator=必须要调用基类的operator=完成基类的复制。
  4. 派生类的析构函数会在被调用完成后自动调用基类的析构函数清理基类成员。因为这样才能保证派生类对象先清理派生类成员再清理基类成员的顺序。
  5. 派生类对象初始化先调用基类构造再调派生类构造。
  6. 派生类对象析构清理先调用派生类析构再调基类的析构。
  7. 因为后续一些场景析构函数需要构成重写,重写的条件之一是函数名相同。那么编译器会对析构函数名进行特殊处理,处理成destrutor(),所以父类析构函数不加virtual的情况下,子类析构函数和父类析构函数构成隐藏关系。

5 继承与友元、静态成员

5.1 继承与友元

友元关系不能继承,(父亲的朋友不是儿子的朋友,除非父亲介绍你们认识)

5.2 继承与静态成员

基类定义了static静态成员,则整个继承体系里面只有一个这样的成员。无论派生出多少个子类,都只有一个static成员实例 。

因为静态成员是存放在静态区


6 复杂的菱形继承及菱形虚拟继承

单继承:一个子类只有一个直接父类时称这个继承关系为单继承
在这里插入图片描述

多继承:一个子类有两个或以上直接父类时称这个继承关系为多继承
![[Pasted image 20240310201225.png]]

菱形继承:一种特殊的情形
![[Pasted image 20240310201253.png]]

从下面的对象成员模型构造,可以看出菱形继承有数据冗余和二义性的问题。
在Assistant的对象中Person成员会有两份。
![[Pasted image 20240310201400.png]]

解决方式:在腰线位置采用虚拟继承。需要注意的是,虚拟继承不要在其他地方去使用
![[Pasted image 20240310201641.png]]

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

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

相关文章

力扣--深度优先算法/回溯算法216.组合总和 Ⅲ

思路分析&#xff1a; 深度优先搜索 (DFS)&#xff1a; 通过递归实现&#xff0c;尝试从数字 1 到 9 中选择可能的数字&#xff0c;构建和为 n&#xff0c;长度为 k 的组合。递归函数 dfs&#xff1a; 接收参数&#xff1a;result 为最终结果集&#xff0c;path 为当前正在生成…

STM32---IIC通信协议(含源码,小白进)

写在前面&#xff1a;在前面的学习过程中&#xff0c;我们学习了串口通信的USART&#xff08;通用同步异步收发器&#xff09;&#xff0c;本节我们将继续学习一种串行通信协议——IIC通信协议。之前我使用51单片机也分享过相关的IIC通信的知识&#xff0c;其实本质的知识是相通…

一. 并行处理与GPU体系架构-并行处理简介

目录 前言0. 简述1. 串行处理与并行处理的区别2. 并行执行3. 容易混淆的几个概念4. 常见的并行处理总结参考 前言 自动驾驶之心推出的 《CUDA与TensorRT部署实战课程》&#xff0c;链接。记录下个人学习笔记&#xff0c;仅供自己参考 本次课程我们来学习下课程第一章——并行处…

开发程序员转金融finance、量化quant的解决方案(含CPA、CFA、CQF等证书要求)

开发程序员转金融finance、量化quant的解决方案&#xff08;含CPA、CFA、CQF等证书要求&#xff09; 文章目录 一、开发程序员转金融 & 量化二、金融行业相关证书&#xff08;CPA、CFA等&#xff09;三、量化分析相关证书&#xff08;CQF等&#xff09;1、量化行业准入门槛…

AI代码加速器即将发布!傅盛:程序员会写某种代码就能找到工作的时代一去不复返了

在产品介绍视频的最后&#xff0c;代码加速器运行了Prompt生成的代码&#xff0c;是一个为傅盛庆生的祝福“彩蛋”。不得不说&#xff0c;猎户星空的程序员就做到了傅盛说的不止写代码&#xff0c;真是有点浪漫小心机在身上的。 3月6日&#xff0c;猎豹移动董事长兼CEO、猎户星…

芯片工程系列(2)传统封装(引线键合与裸片贴装)

英文缩写 Die&#xff1a;即为wafer上切割出来的芯片Wire Bonding&#xff1a;引线键合Dicing&#xff1a;晶圆切割Bias voltage&#xff1a;偏压lead frame&#xff1a;引线框架First Bond&#xff1a;一次键合Second Bond&#xff1a;二次键合PCB&#xff1a;印制电路板&…

怎么在运行框执行脚本和软件?

1.新建一个文件夹&#xff08;随便命名&#xff09; 2.右击此电脑点击属性 3.点击高级系统设置 4.点击环境变量 5.选中Path,点击编辑 6.点击编辑&#xff0c;粘贴你刚刚文件夹的地址 7.所有窗口全部点击确定 8.你可以把常用的软件快捷方式复制到文件夹里&#xff08;比如微…

AHU 汇编 实验一

一、实验名称&#xff1a;实验1 实验1 用Debug命令查看寄存器和内存中的内容 实验目的:求掌握使用Debug命令查看寄存器和内存的方法。 通过第2章两个简单实例认识汇编语言程序&#xff0c;初步了解程序格式&#xff1b;段定义&#xff1b;标号&#xff1b;DOS系统功能&#xf…

基于Java的在线课程教学系统(Vue.js+SpringBoot)

目录 一、摘要1.1 系统介绍1.2 项目录屏 二、研究内容2.1 课程类型管理模块2.2 课程管理模块2.3 课时管理模块2.4 课程交互模块2.5 系统基础模块 三、系统设计3.1 用例设计3.2 数据库设计 四、系统展示4.1 管理后台4.2 用户网页 五、样例代码5.1 新增课程类型5.2 网站登录5.3 课…

什么是物联网?物联网如何工作?

物联网到底是什么&#xff1f; 物联网(Internet of Things&#xff0c;IoT)的概念最早于1999年被提出&#xff0c;官方解释为“万物相连的互联网”&#xff0c;是在互联网基础上延伸和扩展&#xff0c;将各种信息传感设备与网络结合起来而形成的一个巨大网络&#xff0c;可以实…

Linux文件系列: 深入理解缓冲区和C标准库的简单模拟实现

Linux文件系列: 深入理解缓冲区和C标准库的简易模拟实现 一.缓冲区的概念和作用二.一个样例三.理解样例1.样例解释2.什么是刷新? 四.简易模拟实现C标准库1.我们要实现的大致框架2.mylib.h的实现1.文件结构体的定义2.myfopen等等函数的声明3.完整mylib.h代码 3.myfopen函数的实…

xss——权限维持,钓鱼

后台植入cookie&#xff0c;表单劫持&#xff08;获得web权限才可以使用的&#xff09; 把后门植入后&#xff0c;当重新登录后台&#xff0c;就会触发这个代码&#xff0c;将数据发送给xss平台 第二种 我们可以通过这个找到&#xff0c;密码发送的地方&#xff0c;然后就可以…