C++进阶:继承
文章目录
- 继承的概念
- 继承的定义方式
- 继承关系和访问限定符
- 基类和派生类对象的赋值转换
- 继承中的作用域
- 派生类中的默认成员函数
- 构造函数
- 拷贝构造函数
- 赋值拷贝函数
- 析构函数
- 总结

继承的概念
继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保
持原有类特性的基础上进行扩展,增加功能,这样产生新的类,称派生类。继承呈现了面向对象
程序设计的层次结构,体现了由简单到复杂的认知过程。以前我们接触的复用都是函数复用,继
承是类设计层次的复用。
继承中的一些概念:
基类:被一个类继承的类叫做基类。
派生类:继承另一个类的类叫做派生类。
继承的使用场景,当我们有很多个类时,很多个类都有一些共同的特性,有共同的成员变量或者成员函数时,我们就可以把这些特性封装成一个公共的基类,再通过这些类继承这个公共的基类,如果个别类有独特的特性的话,可以单独写在成员变量或者成员函数当中。
继承的定义方式
class A
{
private:public:int _a;
};
class B :public A
{
public:private:int _b;
};
上面的代码是B类继承A类,A类作为基类,B类作为派生类
继承关系和访问限定符
继承方式有三种,public继承,private继承,protected继承,继承方式可以显示写,也可以不写,如果不写的话,class的默认继承方式是private,struct默认继承方式是public。
访问限定符有三种:public,private,protected
这里有一个规则 : 基类的私有成员在子类都是不可见。基类的其他成员在子类的访问方式 = Min(成员在基类的访问限定符,继承方式)public > protected>private。大概规则就是在继承方式和访问限定符中取最小的一个,如果访问限定符是public,但是继承方式是private,那么最后就取private,就不能访问基类成员,只要有private就不能访问基类的成员。
注意:这里这是不能访问,但是还是继承了
可以看到这里是继承了,但是不能访问
如果对访问方式还是不清楚的,可以看看上面的表格,再看看上面的规则。
总结:
- 基类private成员在派生类中无论以什么方式继承都是不可见的。这里的不可见是指基类的私
有成员还是被继承到了派生类对象中,但是语法上限制派生类对象不管在类里面还是类外面
都不能去访问它。 - 基类private成员在派生类中是不能被访问,如果基类成员不想在类外直接被访问,但需要在
派生类中能访问,就定义为protected。可以看出保护成员限定符是因继承才出现的。 - 实际上面的表格我们进行一下总结会发现,基类的私有成员在子类都是不可见。基类的其他
成员在子类的访问方式 == Min(成员在基类的访问限定符,继承方式)public > protected> private。 - 使用关键字class时默认的继承方式是private,使用struct时默认的继承方式是public,不过
最好显示的写出继承方式。 - 在实际运用中一般使用都是public继承,几乎很少使用protetced/private继承,也不提倡
使用protetced/private继承,因为protetced/private继承下来的成员都只能在派生类的类里
面使用,实际中扩展维护性不强
基类和派生类对象的赋值转换
class A
{
private:public:int _a;
};
class B :public A
{
public:B(){}
private:int _b;
};
对于上面这个类来说,我们做以下事情。
int main()
{B b;A a;a = b;A& ref = b;A* Ptr = &b;return 0;
}
这是不是类型转换呢?很显然a和b不是一个类型,如果我们只看赋值操作的话,可能还会认为可能是类型转换,但是如果我们看看下面的引用ref等于b的话就会打消这个念头了,我们知道类型转换会产生临时变量,临时变量具有常性,所以这里引用不能引用一个具有常性的变量,所以这里应该加const,但是实践过程当中这里并没有报错,所以这里肯定不是类型转换,这里是一个特殊规则:赋值兼容转换。
什么事赋值兼容转换呢?
派生类对象 可以赋值给 基类的对象 / 基类的指针 / 基类的引用。这里有个形象的说法叫切片
或者切割。寓意把派生类中父类那部分切来赋值过去。
我们可以这样理解:
赋值兼容转换可以理解为,我们将一个派生类拷贝给一个基类实际上是把派生类中的基类部分拿出来单独给基类,这里就像切片一样,把派生类切开,把基类的部分给基类,所以这里才取名为切片或者切割。
int main()
{B b;A a;a = b;A& ref = b;A* Ptr = &b;return 0;
}
这里如果我们 改变ref对应的成员变量相应的b中的对应的继承下来的成员变量也会变,指针也相同,这里我们讨论的是public情况下,如果是private就不能进行赋值兼容转换。
继承中的作用域
首先我们讨论一下,基类和派生类中是否可以存在相同的函数或者变量,答案是肯定的,首先作用域不同,可以存在相同的函数或者变量。
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;}
};
对于上面这两个类来说,下面这个函数调用的是哪个fun呢?
void Test()B b;b.fun(10);
};
这里很显然调用的是B中的fun(),因为有参数,但是下面这个呢?
void Test()B b;b.fun();
};
上面这个调用的哪个fun呢?这里就不卖关子了,这里会报错。
这里直接会报编译错误,如果我们想调用A类中的函数怎么办呢?
我们可以像下面一样调用。
void Test()
{B b;b.A::fun();
};
像上面这样调用就可以直接调用A类中的相同函数。
这里我们提一下,这两个同名函数的关系,这两个同名函数构成隐藏。
派生类中的默认成员函数
构造函数
由于我们是先继承的基类的成员,所以我们实例化的时候,也是先定义的基类的成员,所以在初始化的时候我们也是先初始化基类的成员变量
可以看到这里先初始化的是基类的成员,即便我将基类的构造函数写在初始化列表的后面,根据这个也可以断定基类的成员变量是在派生类原本的成员变量之前定义的,因为初始化列表的初始化顺序是和声明的顺序一致的,这说明在派生类中继承的基类的成员是先声明的,这也说明应该先初始化基类成员再初始化派生类成员。
拷贝构造函数
class A
{
public:A(int a = 0):_a(a){}A(const A& a):_a(a._a){}
private:int _a;
};
class B : public A
{
public:B(int a = 0, int b = 0):_b(b),A(a){}B(const B& b):_b(b._b),A(b){}
private:int _b;
};
对于拷贝构造来说这里就要用到刚刚我们刚刚讲到的切片,也就是赋值兼容转换,如果是派生类的成员变量的话,就直接走初始化列表直接进行初始化,但是对于基类的成员这里我们直接调用基类的默认的拷贝构造函数,这里我们直接传的变量是类型为B的,这里会做一个切片,直接将属于传递过去用的是A类接收,所以这里会做一个切片,传递过去只接受了A类的部分。
赋值拷贝函数
//A类的赋值拷贝函数A& operator=(const A& a){_a = a._a;}//B类的赋值拷贝函数B& operator=(const B& b){_b = b._b;A::operator=(b);}
需要注意的是,我们在复用基类的赋值拷贝函数的时候,需要说明一下作用域,因为两个赋值拷贝函数构成隐藏,所以调用的时候会优先调用派生类的赋值拷贝函数,所以这里如果不指定作用域的话,会出现无穷递归,很明显下面就出现了无穷递归,所以这里要指定作用域。
析构函数
对于析构函数来说,首先我们要知道的是,在我们调用构造函数的时候,先初始化的是基类的成员,所以应该是基类成员先初始化,然后再初始化派生类自身的成员,所以这里应该是基类的成员先入栈,派生类再入栈,所以这里我们应该先保证先析构派生类的成员变量,再析构基类的成员变量,我们需要保证这一点,由于C++的机制,C++在析构完派生类的成员变量的时候,会直接自动调用基类的析构函数,所以我们并不用显示调用析构函数,但是如果我们也可以显示调用。
这里是因为多态的某些原因,后面细讲。
这里应该指定作用域,所以应该像下面一样调用。
但是我们可以看见,一个对象调用了两次析构,而且还是先析构的是基类成员,所以这里我们就不需要显示写出来,直接等编译器自动调用即可。
总结
继承是面向对象编程中的一个核心概念,通过它我们能够实现代码的重用和扩展。在本篇博客中,我们从继承的基本概念开始,逐步深入探讨了继承的定义方式、继承关系中的访问限定符以及基类和派生类对象之间的赋值转换。我们还讨论了继承中的作用域问题以及派生类中的默认成员函数,包括构造函数、拷贝构造函数、赋值拷贝函数和析构函数。
特别地,我们重点分析了析构函数在多态性中的作用。通过将基类的析构函数声明为虚函数,确保在基类指针指向派生类对象时,能够正确调用派生类的析构函数,从而避免资源泄露和内存管理问题。
通过这些内容的学习,我们不仅理解了继承的基本原理和实现方法,还掌握了如何在实际编程中应用这些知识,提高代码的可维护性和扩展性。希望这些内容能为大家提供有价值的参考,帮助大家更好地理解和应用继承这一重要的编程概念。
相关文章:

C++进阶:继承
文章目录 继承的概念继承的定义方式继承关系和访问限定符基类和派生类对象的赋值转换继承中的作用域派生类中的默认成员函数构造函数拷贝构造函数赋值拷贝函数析构函数 总结 继承的概念 继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段,它允…...
SFTP工具
SFTP工具 工具类配置类调用 工具类 Slf4j Component public class SFTPUtils {Resourceprivate SftpConfig sftpConfig;Session session null;Channel channel null;/*** 网络图片url** param fileUrl* throws JSchException*/public String uploadFileSFTP(String fileUrl) …...

服务器数据恢复—vxfs文件系统元数据被破坏的数据恢复案例
服务器存储数据恢复环境: 某品牌MSA2000服务器存储中有一组由8块SAS硬盘组建的raid5磁盘阵列,其中包含一块热备盘。分配了6个LUN,均分配给HP-Unix小机使用。磁盘分区由LVM进行管理,存放的数据主要为Oracle数据库及OA服务端。 服务…...

【SCAU数据挖掘】数据挖掘期末总复习题库简答题及解析——上
1.K-Means 假定我们对A、B、C、D四个样品分别测量两个变量,得到的结果见下表。 样品 变量 X1X2 A 5 3 B -1 1 C 1 -2 D -3 -2 利用K-Means方法将以上的样品聚成两类。为了实施均值法(K-Means)聚类,首先将这些样品随意分成两类(A、B)和(C、…...
云时代的Java:在云环境中实施Java的最佳实践
引言 云计算已经成为现代软件开发不可或缺的一部分,它提供了灵活性、可扩展性和成本效益。对于Java开发者来说,掌握在云环境中部署和管理Java应用的最佳实践是至关重要的。本文将探讨一些关键策略,帮助你最大化Java在云平台上的性能和效率。…...
STL - 常用算法
概述: 算法主要是由头文件<algorithm><functional><numeric>组成<algorithm>是所有STL头文件中最大的一个,范围涉及比较、 交换、查找、遍历操作、复制、修改等等<numeric>体积很小,只包括几个在序列上面进行…...
Qt | QTextStream 类(文本流)
01、字符编码 1、怎样将字符转换为二进制形式进行存储,存在一个编码的问题,通常都需进行两次编码, 2、字符集:字符的第一次编码是将字符编码为与一个数值(如一个 10 进制整数)相对应,比如把字符 A 编码为 10 进制的 65,B 编码为 66 等。把每一个字符都编码为与一个数值…...

Python学习笔记7:入门知识(七)
前言 之前说过我更换了新的学习路线,现在是根据官方文档和书籍Python crash course来进行学习的,在目前的学习中,对于之前的知识有一些遗漏,这里进行补充。 学习资料有两个,书籍中文版PDF,关注我私信发送…...

如何翻译和本地化游戏?翻译访谈
如何翻译和本地化游戏?这个过程的技术细节有哪些?游戏翻译不同于电影翻译。Logrus IT游戏本地化部门负责人阿列克谢费奥多罗夫(Alexey Fedorov)在接受RUDN语言学系外语系教授和研究人员的采访时谈到了这一点,他是由尤利…...

[C++] 从零实现一个ping服务
💻文章目录 前言ICMP概念报文格式 Ping服务实现系统调用函数具体实现运行测试 总结 前言 ping命令,因为其简单、易用等特点,几乎所有的操作系统都内置了一个ping命令。如果你是一名C初学者,对网络编程、系统编程有所了解ÿ…...

2024网络安全学习路线 非常详细 推荐学习
关键词:网络安全入门、渗透测试学习、零基础学安全、网络安全学习路线 首先咱们聊聊,学习网络安全方向通常会有哪些问题 1、打基础时间太长 学基础花费很长时间,光语言都有几门,有些人会倒在学习 linux 系统及命令的路上&#…...

STM32F103ZET6_HAL_CAN
1定义时钟 2定义按键 按键上拉电阻 3开启串口 4打开CAN(具体什么意思上一篇讲了) 5生成代码 /* USER CODE BEGIN Header */ /********************************************************************************* file : main.c* brief …...

javaWeb项目-ssm+vue网上租车系统功能介绍
本项目源码:java-基于ssmvue的网上租车系统源码说明文档资料资源-CSDN文库 项目关键技术 开发工具:IDEA 、Eclipse 编程语言: Java 数据库: MySQL5.7 框架:ssm、Springboot 前端:Vue、ElementUI 关键技术:springboot、…...

Go模板页面浏览器显示HTML源码问题
<!--* Title: This is a file for ……* Author: JackieZheng* Date: 2024-06-09 17:00:01* LastEditTime: 2024-06-09 17:01:12* LastEditors: Please set LastEditors* Description:* FilePath: \\GoCode\\templates\\index.html --> <!DOCTYPE html> <html …...

弃用Docker Desktop:在WSL2中玩转Docker之Docker Engine 部署与WSL入门
Docker技术概论 在WSL2中玩转Docker之Docker Engine部署 - 文章信息 - Author: 李俊才 (jcLee95) Visit me at CSDN: https://jclee95.blog.csdn.netMy WebSite:http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAddress of this article:https://bl…...

Mac下载了docker,在终端使用docker命令时用不了
问题:在mac使用docker的时候,拉取docker镜像失败 原因:docker是需要用app使用的 ,所以在使用的时候必须打开这个桌面端软件才可以在终端上使用docker命令!!!...

Spring Security——基于MyBatis
目录 项目总结 新建一个项目 pom.xml application.properties配置文件 User实体类 UserMapper映射接口 UserService访问数据库中的用户信息 WebSecurityConfig配置类 MyAuthenticationFailureHandler登录失败后 MyAuthenticationSuccessHandlerw登录成功后 WebSecur…...

Qt——升级系列(Level Four):控件概述、QWidget 核心属性、按钮类控件
目录 控件概述 QWidget 核心属性 核心属性概览 enabled geometry windowTitle windowIcon windowOpacity cursor font toolTip focusPolicy styleSheet 按钮类控件 Push Button Radio Buttion Check Box Tool Button 控件概述 Widget 是 Qt 中的核⼼概念. 英⽂原义是 "…...

品质卓越为你打造App UI 风格
品质卓越为你打造App UI 风格...
ei期刊和sci期刊的区别
ei期刊和sci期刊的区别 ei期刊和sci期刊的区别是什么?Sci和ei都属于国际期刊的一种,但是二者之间存在一些区别,选择期刊投稿时需要注意这些区别。EI期刊刊物的审查周期短,SCI学术期刊的审查期长。难度要求不同,SCI期刊比EI期刊对…...

地震勘探——干扰波识别、井中地震时距曲线特点
目录 干扰波识别反射波地震勘探的干扰波 井中地震时距曲线特点 干扰波识别 有效波:可以用来解决所提出的地质任务的波;干扰波:所有妨碍辨认、追踪有效波的其他波。 地震勘探中,有效波和干扰波是相对的。例如,在反射波…...
Linux链表操作全解析
Linux C语言链表深度解析与实战技巧 一、链表基础概念与内核链表优势1.1 为什么使用链表?1.2 Linux 内核链表与用户态链表的区别 二、内核链表结构与宏解析常用宏/函数 三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势5.1 插入效率5.2 安全…...

8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂
蛋白质结合剂(如抗体、抑制肽)在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上,高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术,但这类方法普遍面临资源消耗巨大、研发周期冗长…...

MODBUS TCP转CANopen 技术赋能高效协同作业
在现代工业自动化领域,MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步,这两种通讯协议也正在被逐步融合,形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...

SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现
摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序,以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务,提供稳定高效的数据处理与业务逻辑支持;利用 uniapp 实现跨平台前…...
linux 下常用变更-8
1、删除普通用户 查询用户初始UID和GIDls -l /home/ ###家目录中查看UID cat /etc/group ###此文件查看GID删除用户1.编辑文件 /etc/passwd 找到对应的行,YW343:x:0:0::/home/YW343:/bin/bash 2.将标红的位置修改为用户对应初始UID和GID: YW3…...

CMake 从 GitHub 下载第三方库并使用
有时我们希望直接使用 GitHub 上的开源库,而不想手动下载、编译和安装。 可以利用 CMake 提供的 FetchContent 模块来实现自动下载、构建和链接第三方库。 FetchContent 命令官方文档✅ 示例代码 我们将以 fmt 这个流行的格式化库为例,演示如何: 使用 FetchContent 从 GitH…...

UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)
UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中,UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化…...
Android第十三次面试总结(四大 组件基础)
Activity生命周期和四大启动模式详解 一、Activity 生命周期 Activity 的生命周期由一系列回调方法组成,用于管理其创建、可见性、焦点和销毁过程。以下是核心方法及其调用时机: onCreate() 调用时机:Activity 首次创建时调用。…...

基于 TAPD 进行项目管理
起因 自己写了个小工具,仓库用的Github。之前在用markdown进行需求管理,现在随着功能的增加,感觉有点难以管理了,所以用TAPD这个工具进行需求、Bug管理。 操作流程 注册 TAPD,需要提供一个企业名新建一个项目&#…...