当前位置: 首页 > news >正文

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就不能访问基类的成员。
注意:这里这是不能访问,但是还是继承了
在这里插入图片描述
可以看到这里是继承了,但是不能访问
在这里插入图片描述
如果对访问方式还是不清楚的,可以看看上面的表格,再看看上面的规则。
总结:

  1. 基类private成员在派生类中无论以什么方式继承都是不可见的。这里的不可见是指基类的私
    有成员还是被继承到了派生类对象中,但是语法上限制派生类对象不管在类里面还是类外面
    都不能去访问它。
  2. 基类private成员在派生类中是不能被访问,如果基类成员不想在类外直接被访问,但需要在
    派生类中能访问,就定义为protected。可以看出保护成员限定符是因继承才出现的。
  3. 实际上面的表格我们进行一下总结会发现,基类的私有成员在子类都是不可见。基类的其他
    成员在子类的访问方式 == Min(成员在基类的访问限定符,继承方式)public > protected> private。
  4. 使用关键字class时默认的继承方式是private,使用struct时默认的继承方式是public,不过
    最好显示的写出继承方式。
  5. 在实际运用中一般使用都是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)机制是面向对象程序设计使代码可以复用的最重要的手段&#xff0c;它允…...

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文件系统元数据被破坏的数据恢复案例

服务器存储数据恢复环境&#xff1a; 某品牌MSA2000服务器存储中有一组由8块SAS硬盘组建的raid5磁盘阵列&#xff0c;其中包含一块热备盘。分配了6个LUN&#xff0c;均分配给HP-Unix小机使用。磁盘分区由LVM进行管理&#xff0c;存放的数据主要为Oracle数据库及OA服务端。 服务…...

【SCAU数据挖掘】数据挖掘期末总复习题库简答题及解析——上

1.K-Means 假定我们对A、B、C、D四个样品分别测量两个变量&#xff0c;得到的结果见下表。 样品 变量 X1X2 A 5 3 B -1 1 C 1 -2 D -3 -2 利用K-Means方法将以上的样品聚成两类。为了实施均值法(K-Means)聚类&#xff0c;首先将这些样品随意分成两类(A、B)和(C、…...

云时代的Java:在云环境中实施Java的最佳实践

引言 云计算已经成为现代软件开发不可或缺的一部分&#xff0c;它提供了灵活性、可扩展性和成本效益。对于Java开发者来说&#xff0c;掌握在云环境中部署和管理Java应用的最佳实践是至关重要的。本文将探讨一些关键策略&#xff0c;帮助你最大化Java在云平台上的性能和效率。…...

STL - 常用算法

概述&#xff1a; 算法主要是由头文件<algorithm><functional><numeric>组成<algorithm>是所有STL头文件中最大的一个&#xff0c;范围涉及比较、 交换、查找、遍历操作、复制、修改等等<numeric>体积很小&#xff0c;只包括几个在序列上面进行…...

Qt | QTextStream 类(文本流)

01、字符编码 1、怎样将字符转换为二进制形式进行存储,存在一个编码的问题,通常都需进行两次编码, 2、字符集:字符的第一次编码是将字符编码为与一个数值(如一个 10 进制整数)相对应,比如把字符 A 编码为 10 进制的 65,B 编码为 66 等。把每一个字符都编码为与一个数值…...

Python学习笔记7:入门知识(七)

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

如何翻译和本地化游戏?翻译访谈

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

[C++] 从零实现一个ping服务

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

2024网络安全学习路线 非常详细 推荐学习

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

STM32F103ZET6_HAL_CAN

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

javaWeb项目-ssm+vue网上租车系统功能介绍

本项目源码&#xff1a;java-基于ssmvue的网上租车系统源码说明文档资料资源-CSDN文库 项目关键技术 开发工具&#xff1a;IDEA 、Eclipse 编程语言: Java 数据库: MySQL5.7 框架&#xff1a;ssm、Springboot 前端&#xff1a;Vue、ElementUI 关键技术&#xff1a;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&#xff1a;http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAddress of this article:https://bl…...

Mac下载了docker,在终端使用docker命令时用不了

问题&#xff1a;在mac使用docker的时候&#xff0c;拉取docker镜像失败 原因&#xff1a;docker是需要用app使用的 &#xff0c;所以在使用的时候必须打开这个桌面端软件才可以在终端上使用docker命令&#xff01;&#xff01;&#xff01;...

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都属于国际期刊的一种&#xff0c;但是二者之间存在一些区别&#xff0c;选择期刊投稿时需要注意这些区别。EI期刊刊物的审查周期短&#xff0c;SCI学术期刊的审查期长。难度要求不同&#xff0c;SCI期刊比EI期刊对…...

反向工程与模型迁移:打造未来商品详情API的可持续创新体系

在电商行业蓬勃发展的当下&#xff0c;商品详情API作为连接电商平台与开发者、商家及用户的关键纽带&#xff0c;其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息&#xff08;如名称、价格、库存等&#xff09;的获取与展示&#xff0c;已难以满足市场对个性化、智能…...

《Playwright:微软的自动化测试工具详解》

Playwright 简介:声明内容来自网络&#xff0c;将内容拼接整理出来的文档 Playwright 是微软开发的自动化测试工具&#xff0c;支持 Chrome、Firefox、Safari 等主流浏览器&#xff0c;提供多语言 API&#xff08;Python、JavaScript、Java、.NET&#xff09;。它的特点包括&a…...

汽车生产虚拟实训中的技能提升与生产优化​

在制造业蓬勃发展的大背景下&#xff0c;虚拟教学实训宛如一颗璀璨的新星&#xff0c;正发挥着不可或缺且日益凸显的关键作用&#xff0c;源源不断地为企业的稳健前行与创新发展注入磅礴强大的动力。就以汽车制造企业这一极具代表性的行业主体为例&#xff0c;汽车生产线上各类…...

系统设计 --- MongoDB亿级数据查询优化策略

系统设计 --- MongoDB亿级数据查询分表策略 背景Solution --- 分表 背景 使用audit log实现Audi Trail功能 Audit Trail范围: 六个月数据量: 每秒5-7条audi log&#xff0c;共计7千万 – 1亿条数据需要实现全文检索按照时间倒序因为license问题&#xff0c;不能使用ELK只能使用…...

视频字幕质量评估的大规模细粒度基准

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 摘要 视频字幕在文本到视频生成任务中起着至关重要的作用&#xff0c;因为它们的质量直接影响所生成视频的语义连贯性和视觉保真度。尽管大型视觉-语言模型&#xff08;VLMs&#xff09;在字幕生成方面…...

ElasticSearch搜索引擎之倒排索引及其底层算法

文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...

WordPress插件:AI多语言写作与智能配图、免费AI模型、SEO文章生成

厌倦手动写WordPress文章&#xff1f;AI自动生成&#xff0c;效率提升10倍&#xff01; 支持多语言、自动配图、定时发布&#xff0c;让内容创作更轻松&#xff01; AI内容生成 → 不想每天写文章&#xff1f;AI一键生成高质量内容&#xff01;多语言支持 → 跨境电商必备&am…...

AI编程--插件对比分析:CodeRider、GitHub Copilot及其他

AI编程插件对比分析&#xff1a;CodeRider、GitHub Copilot及其他 随着人工智能技术的快速发展&#xff0c;AI编程插件已成为提升开发者生产力的重要工具。CodeRider和GitHub Copilot作为市场上的领先者&#xff0c;分别以其独特的特性和生态系统吸引了大量开发者。本文将从功…...

【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统

目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索&#xff08;基于物理空间 广播范围&#xff09;2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...

优选算法第十二讲:队列 + 宽搜 优先级队列

优选算法第十二讲&#xff1a;队列 宽搜 && 优先级队列 1.N叉树的层序遍历2.二叉树的锯齿型层序遍历3.二叉树最大宽度4.在每个树行中找最大值5.优先级队列 -- 最后一块石头的重量6.数据流中的第K大元素7.前K个高频单词8.数据流的中位数 1.N叉树的层序遍历 2.二叉树的锯…...