【C++进阶】继承
【C++进阶】继承
🥕个人主页:开敲🍉
🔥所属专栏:C++🥭
🌼文章目录🌼
1. 继承的概念及定义
1.1 继承的概念
1.2 继承定义
1.2.1 定义格式
1.2.2 继承父类成员访问方式的变化
1.3 继承类模板
2. 父类和子类对象赋值兼容转换
3. 继承中的作用域
3.1 隐藏规则:
4. 子类的默认成员函数
4.1 4个常见默认成员函数
4.2 实现一个无法被继承的类
5. 继承与友元
6. 继承与静态成员
7. 多继承及灵性继承问题
7.1 继承模型
7.2 虚继承
7.3 多继承中的指针偏移问题
8. 继承和组合
8.1 继承和组合
1. 继承的概念及定义
1.1 继承的概念
继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段,它允许我们在保持原有类特性的基础上进行扩展,增加方法(成员函数)和属性(成员变量),这样产生新的类,称子类。继承呈现了面向对象程序设计的层次结构,体现了由简单到复杂的认知过程。以前我们接触的函数层次的复用,继承是类设计层次的复用。
下⾯我们看到没有继承之前我们设计了两个类Student和Teacher,Student和Teacher都有姓名/地址/电话/年龄等成员变量,都有identity⾝份认证的成员函数,设计到两个类里面就是冗余的。当然他们也有⼀些不同的成员变量和函数,比如老师独有成员变量是职称,学⽣的独有成员变量是学号;学⽣的独有成员函数是学习,老师的独有成员函数是授课。
class Teacher
{
public:
void identity()
{
//身份认证
}
private:
size_t _age;//年龄
string _name;//姓名
string _address;//地址
string _tel;//电话string _title;//学号
};
class Student
{
private:
size_t _age;//年龄
string _name;//姓名
string _address;//地址
string _tel;//电话string _stuid;//职称
};
下面我们公共的成员都放到Person类中,Student和teacher都继承Person,就可以复用这些成员,就不需要重复定义了,省去了很多麻烦。
class Person
{
public:
public:
void identity()
{
//身份认证
}size_t _age;//年龄
string _name;//姓名
string _address;//地址
string _tel;//电话
};
class Teacher:public Person
{
private:
string _title;//学号
};
class Student:public Person
{
private:
string _stuid;//职称
};
1.2 继承定义
1.2.1 定义格式
从上面我们看到,Person是父类,也可以称为基类,Student和Teacher是子类,也可以称为派生类。继承方式如下图:
可以看到,这里的继承方式所用的关键字和我们访问限定符的关键字是一样的:
1.2.2 继承父类成员访问方式的变化
总结如下:
子类中的父类成员的访问方式取决于 父类对这些成员的访问限定符与继承方式 中权限较小的。
比如,父类的成员用private限定,继承方式用public,那么实际上父类中的成员继承到子类中后,也是private,因此子类虽然继承了父类的成员,但是不可访问。
1.3 继承类模板
这里我们实现一个栈的类,继承的是库中的vector,因此我们在实现栈的功能:尾插、尾删、获取栈顶元素等操作时,就可以调用vector中的函数。
2. 父类和子类对象赋值兼容转换
① public继承的子类对象可以赋值给父类的对象/父类的指针/父类的引用。这里有个形象的说法叫切片或者切割。寓意把子类中父类那部分切来赋值过去。
② 父类对象不能赋值给子类对象。
3. 继承中的作用域
3.1 隐藏规则:
① 在继承体系中父类和子类都有独立的作用域。
② 子类和父类中有同名成员,子类中将会屏蔽对父类中的同名成员的直接访问,这种情况叫隐藏。如果想要访问父类中的同名成员,使用 父类 :: 同名成员 即可访问。
③ 子类和父类中的成员函数只要函数名相同就构成隐藏,不受其他因素限制。
④ 因此在继承体系中不建议定义同名函数。
4. 子类的默认成员函数
4.1 4个常见默认成员函数
默认成员函数是指我们不写,编译器会帮我们自动生成,常见的4个默认成员函数有:构造函数、析构函数、拷贝构造函数、operator=。那么在子类中,这4个默认成员函数是如何生成的呢?
① 子类的构造函数必须调用父类的构造函数初始化父类的那⼀部分成员。如果父类没有默认的构造函数,则必须在子类构造函数的初始化列表阶段显示调用。
② 子类的析构函数会在被调用完成后自动调用父类的析构函数清理父类成员。因为这样才能保证子类对象先清理子类成员再清理父类成员的顺序。
③ 子类对象初始化时先调用父类对象的构造函数再调用子类对象的构造函数。
④ 子类的拷贝构造函数必须调用父类的拷贝构造完成父类的拷贝初始化。
⑤ 子类的operator=必须要调用父类的operator=完成父类的复制。需要注意的是子类的operator=隐藏了父类的operator=,所以显示调用父类的operator=,需要指定父类作用域。
4.2 实现一个无法被继承的类
方法1:将父类的构造函数设为private,因为在构造子类对象时必须要调用父类对象的构造函数,而父类对象的构造函数设为私有无法访问,因此也就无法被继承。
方法2:使用final修饰父类,就不能够被继承了。finale有最后的意思,这里可以理解为最终类。
5. 继承与友元
友元关系不能继承,也就是说父类友元不能访问子类私有和保护成员。
6. 继承与静态成员
父类定义了static静态成员,则整个继承体系里面只有⼀个这样的成员。无论派生出多少个子类,都只有⼀个static成员实例。
7. 多继承及灵性继承问题
7.1 继承模型
单继承:一个子类只有一个父类的情况我们称为单继承。
多继承:一个子类有两个或者两个以上的父类时称为多继承,多继承对象在内存中存储的方式为:先继承的父类在最前面,后面继承的父类按照顺序排列,子类的成员排在最后。
菱形继承:菱形继承是多继承的一种特殊情况。
从上面可以看出,fun2和fun3都继承了fun1,都存有了一份size_t _fun1,而fun0继承了fun2和fun3,因此不可避免地fun0中存有了两份fun1中的size_t _fun1,这就会导致数据冗余和⼆义性。支持多继承就一定会存在菱形继承的问题,实践中使用多继承是务必要小心谨慎。
这里在访问_fun1时系统报错说fun0::_fun1不明确,也就是这里的两份_fun1,系统也不知道你要访问的是哪一份。这就是二义性问题。
7.2 虚继承
那我们在实践中不可避免地要写出菱形继承,但是又想避免数据冗余和⼆义性的问题该如何做呢?这里就需要使用到virtual关键字:
7.3 多继承中的指针偏移问题
来看一道例题:
关于多继承中指针偏移问题,下面选项正确的是()
A. f1==f2==f3 B. f1<f2<f3 C. f1==f3!=f2 D. f1!=f2!=f3
代码:
class fun1
{
public:
size_t _fun1;
};class fun2
{
public:
size_t _fun2;
};
class fun3 :public fun1, public fun2
{
private:
size_t _fun3;
};
int main()
{
fun3 f3;fun1* f1 = &f3;
fun2* f2 = &f3;
return 0;
}
正确答案:C
为什么呢?一张图弄明白:
8. 继承和组合
8.1 继承和组合
① 继承是一种is-a的关系。意思就是每个子类对象都是一个父类对象,就好比是有血缘关系的父子,儿子有自己不同于父亲之处,同时也一定有与父亲的相同之处,相同之处便是子类继承父类的那一部分。
② 继承允许你根据父类的实现来定义子类的实现。这种通过生成子类的复用通常被称为白箱复用
(white-box reuse)。术语“白箱”是相对可视性而言:在继承方式中,父类的内部细节对子类可见
。继承⼀定程度破坏了父类的封装,父类的改变,对子类有很大的影响。子类和父类间的依赖关系
很强,耦合度高。
③ 组合是一种has-a的关系。可以理解为数学中的集合,{1,2,3}和{1,2,3,4,5,6}的关系,前者是后者的子集后者包含前者。
④ 对象组合是类继承之外的另⼀种复用选择。新的更复杂的功能可以通过组装或组合对象来获得。对象组合要求被组合的对象具有良好定义的接口。这种复用风格被称为黑箱复用(black-box reuse),因为对象的内部细节是不可见的。对象只以“黑箱”的形式出现。组合类之间没有很强的依赖关系,耦合度低。优先使用对象组合有助于你保持每个类被封装。
⑤ 优先使用组合,而不是继承。实际尽量多去用组合,组合的耦合度低,代码维护性好。不过也不太那么绝对,类之间的关系就适合继承(is-a)那就用继承,另外要实现多态,也必须要继承。类之间的关系既适合用继承(is-a)也适合组合(has-a),那就用组合。
⑥ 很多人说C++语法复杂,其实多继承就是⼀个体现。有了多继承,就存在菱形继承,有了菱形继承就有菱形虚拟继承,底层实现就很复杂,并不像我们想的那么简单,性能也会有⼀些损失,所以最好不要设计出菱形继承。多继承可以认为是C++的缺陷之一,后来的⼀些编程语⾔都没有多继承,如Java。
创作不易,点个赞呗,蟹蟹啦~
相关文章:

【C++进阶】继承
【C进阶】继承 🥕个人主页:开敲🍉 🔥所属专栏:C🥭 🌼文章目录🌼 1. 继承的概念及定义 1.1 继承的概念 1.2 继承定义 1.2.1 定义格式 1.2.2 继承父类成员访问方式的变化 1.3 继承类模…...

立体相机镜面重建(一)镜面标定
无论是单目、双目或者是多屏幕镜面重建,都需要事先对屏幕和相机的相对位置进行标定,求得相机到屏幕之间的相对变换关系。如果求得屏幕和相机之间的变换关系呢?接下来是标定流程。 (一)准备: 1)…...

【如何有效解决前端Vue中的常见难题】
🐟作者简介:一名大三在校生,喜欢编程🪴 🐙个人主页🥇:Aic山鱼🐠WeChat:z7010cyy 🦈系列专栏:🏞️ 前端-JS基础专栏✨前端-Vue框架专栏…...

CLAMP-1靶机渗透测试
一、靶机下载地址 https://www.vulnhub.com/entry/clamp-101,320/ 二、信息收集 1、主机发现 # 使用命令 nmap 192.168.145.0/24 -sn | grep -B 2 "00:0C:29:88:B4:BF" 2、端口扫描 # 使用命令 nmap 192.168.145.0/24 -p- -sV 3、指纹识别 # 使用命令 whatweb …...

JavaScript中的Truthy Falsy值以及等号判断
1.Falsy & Truthy Falsy的值false,0,-0, “”, null, undefined,NaNTruthy的值除了以上之外的其他值 2.等号判断 console.log(10 10); console.log(0 ); console.log(0 false); console.log( fa…...

uniapp——展开和收起
案例展示 代码 后台返回的数据格式如下: {1: "大富科技速度快放假手动阀",2: "第三方斯蒂芬斯蒂芬是的开发时间",4: "45345345",5: "电饭锅电饭锅地方" }<view class"tipTitle">温馨提示</view> &l…...

WebGL2学习(2): GLSL ES 3.0
更多精彩内容尽在 dt.sim3d.cn ,关注公众号【sky的数孪技术】,技术交流、源码下载请添加VX:digital_twin123 WebGL 2.0 给 GLSL 带来了重大变化。WebGL 1.0 中使用的 GLSL 版本是 GLSL ES 1.0。 WebGL 2.0 中仍然可用。但是,通过编…...

[大模型实战] DAMODEL云算力平台部署LLama3.1大语言模型
[大模型实战] DAMODEL云算力平台部署LLama3.1大语言模型 目录 一、LLama3.1二、DAMODEL云算力平台2.1 提供的服务2.1.1 AI训练2.1.2 AI推理2.1.3 高性能计算2.1.4 图像/视频渲染2.1.5 定制化部署 2.2 支持的GPU 三、在DAMODEL部署LLama3.13.1 在DAMODEL创建实例&…...

驱动开发系列09 - Linux设备模型之设备,驱动和总线
一:概述 Linux 设备模型(LDM)是 Linux 内核中引入的一个概念。用于管理内核对象(那些需要引用计数的对象、例如文件、设备、总线甚至驱动程序),以及描述它们之间的层次结构,以及这些内核对象之间绑定关系。Linux 设备模型引入了对象生命周期管理、引用计数、以及面向对象…...

HTML实现弹出层
leopard/ˈlepərd/ 豹子,豹纹 弹出层指的是鼠标悬停于某个元素之上时显示的一个界面组件。 关注和理解特性:z-index属性和动态生成HTML元素。 HTML5新增: figure:媒体内容(图像,音频,视频),用于包含一…...

Android控件详解
在Android应用程序中,界面由布局和组件组成。布局相当于框架,而控件则是框架里面的内容。了解过Android布局后,如果要设计ui界面,还需要了解和掌握各个控件的应用。 一个界面的设计,先从创建容器开始,再向…...

记忆化搜索专题篇
目录 斐波那契数 不同路径 最长递增子序列 猜数字大小II 矩阵中的最长递增路径 声明:下面将主要使用递归记忆化搜索来解决问题!!! 斐波那契数 题目 思路 斐波那契数的特点就是除了第一个数是0,第二个数是1&…...

入网测评检查项大全(安全资料)
1. Linux操作系统 2. Windows操作系统 3. Tomcat中间件 4. Nginx中间件 5. Mysql数据库 6. Weblogic中间件 7. Oracle数据库 8. Redis数据库 9. 达梦数据库 10. 应用系统 11. 渗透测试 13 .AIX操作系统 14 .中创中间件 15 .IIS中间件 16 .Apache中间件 17 .Mari…...

uni-app 开发App时调用uni-push 实现在线系统消息推送通知 保姆教程
一、引言 在开发App时避免不了需要推送系统通知,以提高用户的使用体验。在自己的一个工具型的小app上全流程接入了uni-push2.0的推送能力,做个记录,以防后期需要用到。在阅读本教程前最好先看看官方文档,结合官方文档使用…...

13.StringRedisTemplete使用
上一篇说到改变了RedisTemplate的默认序列化器后,在redis中存入Java对象后,在redis中的呈现是:会记录类的字节码 这也是代码中可以强制装换为对应的java对象的原因: Test void testStudent() {redisTemplate.opsForValue().set(&q…...

[工具]-gitee+pycharm-配置
安装git 查看git是否安装设置成功: git config user.name git config user.email 码云账号设置邮箱 pycharm设置gitee 打开 PyCharm,在 Settings - Plugins 里面,搜索 Gitee 插件,安装后重启 PyCharm。 pychar…...

中间件是一种在客户端和服务器之间进行通信和处理的软件组件或服务
中间件是一种在客户端和服务器之间进行通信和处理的软件组件或服务。中间件位于应用程序和操作系统之间,可以提供一些功能,如请求转发、数据转换、安全性和身份验证、日志记录等。 中间件的主要作用是将应用程序与底层基础设施解耦,提供了一…...

RCE-eval长度限制突破技巧
目录 一、长度17的限制绕过 1、最简单的绕过 (一)绕过 (二)编写一句话木马 2、文件包含的利用 (一)远程文件包含的利用 (二)本地文件包含的利用 3、usort绕过 (…...

【黑马】MyBatis
目录 MyBatis简介JDBC缺点:MyBatis针对于JDBC进行简化,简化思路: MyBatis快速入门具体构建步骤解决SQL映射文件的警告提示 Mapper代理开发案例:使用Mapper代理方式完成案例具体步骤详解:Mapper代理方式 Mapper核心配置…...

oracle创建dblink使得数据库A能够访问数据库B表LMEAS_MFG_FM的数据
1、给数据库A普通用户CMRONLINE相应的权限,在sys用户下执行以下语句 GRANT CREATE DATABASE LINK TO CMRONLINE; GRANT DROP PUBLIC DATABASE LINK TO CMRONLINE; GRANT CREATE PUBLIC DATABASE LINK TO CMRONLINE; 2、在数据库A用户 CMRONLINE下执行创建语句&…...

git config 如何配置用户账户
Git配置用户账户主要涉及设置用户名和邮箱地址,这是Git进行版本控制时用于标识提交者身份的重要信息。以下是如何配置Git用户账户的详细步骤: 1. 打开命令行工具 首先,需要打开命令行工具(如CMD、Terminal或Git Bash等ÿ…...

SpringBoot基础(二):配置文件详解
SpringBoot基础系列文章 SpringBoot基础(一):快速入门 SpringBoot基础(二):配置文件详解 目录 一、配置文件分类二、配置文件优先级1、不同版本优先级2、不同位置优先级 三、配置文件格式1、yml和yaml格式1.1、字符串1.2、布尔类型1.3、整数型1.4、浮点…...

Web安全(一)-靶场搭建过程-基于docker
今天来复习一下web方面的知识 1.1 sqliab环境搭建 基于Centos 和Docker 1.1.1 Vmware环境安装 这个就略去了吧 博主使用的是vmware17pro 具体的密钥什么的大家懂的都懂 这里就不提供了 接下来 将带大家安装centos7的镜像 为了方便操作 这里选择 centos7_minimal 地址如下:…...

【JavaEE】单例模式和阻塞队列
🔥个人主页: 中草药 🔥专栏:【Java】登神长阶 史诗般的Java成神之路 🕯️一.设计模式 在Java中,设计模式(Design Patterns)是指在软件工程和面向对象编程中,针对特定…...

RCE绕过技巧
目录 EVAL长度限制突破技巧 1.使用反引号 2.file_put_contents写入文件 3.php5.6变长参数usort回调后门 命令长度限制突破技巧 1.拼接文件名 无字母数字的webshell命令执行 1.取反码 2.上传临时文件 EVAL长度限制突破技巧 分析代码:首先传递一个param参数&…...

Spring源码解析(31)之事务配置文件解析以及核心对象创建过程
一、前言 首先我们先准备一下spring 事务的配置文件,具体内容如下: <?xml version"1.0" encoding"UTF-8"?> <beans xmlns"http://www.springframework.org/schema/beans"xmlns:xsi"http://www.w3.org/20…...

win11安装docker报错记录
报错一: Docker Desktop - Unexpected WSL error An unexpected error occurred while executing a WSL command. Either shut down WSL down with wsl --shutdown, and/or reboot your machine. You can also try reinstalling WSL and/or Docker Desktop. If t…...

【vulnhub】CLAMP 1.0.1靶机
信息收集 靶机发现 端口扫描 页面访问,并查看源码 访问 /nt4stopc/,下面有一些问题,提示必须收集答案 一些判断题,对与错对应1与0,最后结果为0110111001,拼接访问 点击图中位置,发现存在参数,p…...

GPS跟踪环路MATLAB之——数字锁相环
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 GPS跟踪环路MATLAB之——数字锁相环 前言为什么要锁相环科斯塔斯环锁相环的一些基本概念1、捕获、锁定与跟踪的概念2、捕获时间和稳态相差3、相位捕获和频率捕获4、捕获带和同…...

docker开发环境搭建-关于数据库的IP是什么
故事的背景是这样的: 我在本地的ubuntu系统上安装了docker,并创建了一个mysql容器,但是在使用DBeaver连接该数据库时,需要填写数据库的ip,填写127.0.0.1,工具提示找不到这个库,然后使用ip addr…...