C++继承(上)

news2024/12/26 23:52:42

我们知道,面向对象有三大特性:封装,继承,多态。封装前面已经说过,这篇文章主要说说继承。
在这里插入图片描述

文章目录

  • 1.继承的概念及定义
    • 1.1继承的概念
    • 1.2 继承定义
      • 1.2.1定义格式
      • 1.2.2继承关系和访问限定符
  • 2. 基类和派生类对象赋值转换
  • 3.继承中的作用域
  • 4.派生类的默认成员函数
    • 4.1 构造
    • 4.2 拷贝构造
    • 4.3 赋值
    • 4.4 析构
  • 5. 如何设计一个不能被继承的类

1.继承的概念及定义

1.1继承的概念

继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行扩展,增加功能,这样产生新的类,称派生类。继承呈现了面向对象程序设计的层次结构,体现了由简单到复杂的认知过程。以前我们接触的复用都是函数复用,继
承是类设计层次的复用

举个例子:
比如说我们学校有个管理系统,管理老师和学生。老师和学生中都会记录他们的名字,电话,年龄等等,但是他们的学校id是不一样的,一个是学号,一个是工号。那么有些数据和方法每个角色都有的,就设计重复了。此时继承就是类设计层次的复用,那么如何使用,我们来看:
在这里插入图片描述
继承后父类的Person的成员(成员函数+成员变量)都会变成子类的一部分。这里体现出了
Student和Teacher复用了Person的成员。
在这里插入图片描述
调用Print可以看到成员函数的复用。那么继承的语法格式是什么样的,我们来看。

1.2 继承定义

1.2.1定义格式

下面我们看到Person是父类,也称作基类。Student是子类,也称作派生类
在这里插入图片描述
这个继承方式又该如何来理解呢?

1.2.2继承关系和访问限定符

继承方式和访问限定符都各有3个:
在这里插入图片描述
所以它们就会组成9种不同的情况:
在这里插入图片描述
那么我们该如何去理解这些呢?
1.基类的私有成员在派生类都是不可见。基类的其它成员在派生类的访问方式 == Min(成员在基类的访问限定符,继承方式),public > protected > private
举个例子:
在这里插入图片描述
派生类继承下来的限制是这两种中小的那个。这里派生类中的_name和_age是protected。
2.基类private成员在派生类中无论以什么方式继承都是不可见的。这里的不可见是指基类的私有成员还是被继承到了派生类对象中,但是语法上限制派生类对象不管在类里面还是类外面都不能去访问它
举个例子:
在这里插入图片描述
在这里插入图片描述
从上面两幅图中可以看出私有的和公有的是一样大的,所以私有的数据被继承下来了。
在这里插入图片描述
继承到了派生类对象中,但是语法上限制派生类对象不管在类里面还是类外面都不能去访问它。

3.基类private成员在派生类中是不能被访问,如果基类成员不想在类外直接被访问,但需要在派生类中能访问,就定义为protected。可以看出保护成员限定符是因继承才出现的
在这里插入图片描述
可以看出派生类中能访问,外面不能访问。以前我们写一个类时,private和protected,两者其实没有什么区别,现在在继承中就能体现它们的区别了。

4.使用关键字class时默认的继承方式是private,使用struct时默认的继承方式是public,不过最好显示的写出继承方式。

5.在实际运用中一般使用都是public继承,几乎很少使用protetced/private继承,也不提倡使用protetced/private继承,因为protetced/private继承下来的成员都只能在派生类的类里面使用,实际中扩展维护性不强

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

派生类对象 可以赋值给 基类的对象 / 基类的指针 / 基类的引用这里有个形象的说法叫切片或者切割。寓意把派生类中父类那部分切来赋值过去。在这里插入图片描述
这里和不同类型的引用不一样,不同类型的引用会产生一个临时变量。但是这里不一样,它是语法天然支持的,没有类型转换。
子类赋值给父类的情况如下
在这里插入图片描述
代码演示:
在这里插入图片描述
从上图可以看出,已经赋值给父类了。这里的赋值是深拷贝,不是浅拷贝。

子类地址给父类指针的情况如下
在这里插入图片描述
是一个指针指向子类的一部分。
子类引用给父类的情况如下
在这里插入图片描述
它是子类一部分的别名。

基类对象不能赋值给派生类对象
在这里插入图片描述
强制类型转换也不行。

基类的指针或者引用可以通过强制类型转换赋值给派生类的指针或者引用。但是必须是基类的指针是指向派生类对象时才是安全的。这里基类如果是多态类型,可以使用RTTI(Run Time Type Information)的dynamic_cast 来进行识别后进行安全转换。(ps:这个我们后面再讲解,这里先了解一下)

3.继承中的作用域

1. 在继承体系中基类和派生类都有独立的作用域
我们知道:同一个域中不能有相同的名字,不同的域中就可以有相同的名字。
2. 子类和父类中有同名成员,子类成员将屏蔽父类对同名成员的直接访问,这种情况叫隐藏,也叫重定义
在这里插入图片描述
那么这里子类和父类都有_id,此时打印会打印谁的呢?
在这里插入图片描述
那么我们也可以在子类成员函数中,可以使用 基类::基类成员 显示访问
在这里插入图片描述
成员函数也是同样的道理,先调用子类自己的。
在这里插入图片描述
如果我们想调用父类的,指定作用域就行。
在这里插入图片描述
3.需要注意的是如果是成员函数的隐藏,只需要函数名相同就构成隐藏
在这里插入图片描述
这两个fun函数是重载还是隐藏关系呢?答案是:隐藏关系。原因是:函数重载要求在同一作用域,而这两个函数在不同的作用域里。
4.注意在实际中在继承体系里面最好不要定义同名的成员

4.派生类的默认成员函数

6个默认成员函数,“默认”的意思就是指我们不写,编译器会变我们自动生成一个,那么在派生类中,这几个成员函数是如何生成的呢?
在这里插入图片描述

4.1 构造

举个例子:
在这里插入图片描述
从这个例子中,我们可以看出什么呢?
子类构造函数原则:
a、调用父类构造函数初始化继承自父类成员

所以继承父类的成员_name还是用父类的构造函数来初始化。
在这里插入图片描述
b、自己再初始化自己的成员 – 规则参考普通类
析构、拷贝构造、复制重载也类似

子类的本身的成员还是去调用子类的来初始化。

那我们显示的写,又是什么情况呢
在这里插入图片描述
显示的去写,也没有办法去构造,只能显示的去传参数
在这里插入图片描述
这样写就像使用匿名对象方式。那么这样写,它是先调用的是子类的构造还是先调用父类构造呢
答案是:先调用父类的。原因是:初始化列表执行的顺序不是我们写的顺序,而是声明的顺序。在子类中,它是认为父类在前,子类在后

4.2 拷贝构造

拷贝构造也是相似的道理:
在这里插入图片描述
父类的成员变量拷贝时,会去调用父类的拷贝构造。子类的成员变量还是调用自己的拷贝构造。这里子类调用的是自己默认的拷贝构造。那么子类的拷贝构造我们该如何去显示写呢?
在这里插入图片描述
父类的显示定义是这样去写的。
在这里插入图片描述
因为拷贝构造是引用,所以我们可以把子类直接传给父类,这样就形成了切片:
在这里插入图片描述
所以它会自动的找子类里面父类成员来拷贝构造。那么什么时候去显示写的,就是当我们子类需要深拷贝的时候就要显示写了。

4.3 赋值

在这里插入图片描述
在这里插入图片描述
这里赋值也是相同的道理,父类的成员去调用父类的赋值函数。子类显示写如下:
在这里插入图片描述
这里就是显示的去调用父类的赋值函数。然后父类的赋值函数也是引用,可以把子类切片。但是这样写会出现栈溢出,原因就是这样写它调用的是子类自己的赋值函数,它把父类的隐藏了。我们要加上类域:
在这里插入图片描述
这里还有一个隐藏的切片,就是this。像s1=s3中,s3转到s会被切割,而this指针也会被切割(也就是s1也会切割)。

4.4 析构

我们先把子类的析构显示的来写:
在这里插入图片描述
我们发现这里显示调用发生了错误。原因是:父子类的析构函数构成隐藏关系,但可能有的同学就会问了,它们的名字不是不相同吗?原因是:多态的需要,析构函数名统一会被处理成destructor()
所以我们就这样写:
在这里插入图片描述
但这样还有一些情况:
在这里插入图片描述
我们只有s1和s2两个对象,子类调用了两次析构,但是父类调用了四次析构。这是为什么呢?
原因是:为了保证析构顺序:先子后父。子类析构函数完成后会自动调用父类析构函数,所以不需要我们显示调用
在这里插入图片描述
为什么一定是先子后父呢?因为父类先构造,然后子类再构造,析构时,子类先析构,父类再析构。然后我们如果要显示的来析构,可能就会导致父类先析构了。就违反了一些规则。

5. 如何设计一个不能被继承的类

我们可以把父类的构造函数设置成私有:
在这里插入图片描述
这样B就无法构造对象了。但此时A自己也不能被构造了啊,我们该怎么办呢?我们可以去写一个函数来构造:
在这里插入图片描述
但是调用类里面的函数必须要有对象,这就产生了死循环。我们可以这样:
在这里插入图片描述
在这里插入图片描述
这样父类自己还可以使用,子类如果继承父类,则不能构造使用。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

vue.js客服系统实时聊天项目开发(十四)点击加载展示历史消息列表

当访客一进去聊天界面以后,需要获取一下历史消息展示到界面,并且需要能分页的原理展示 在顶部有一个加载更多记录的按钮,点击就能按分页获取数据 //展示历史消息记录getHistoryList(){var _thisthis;let pagesize5;this.$axios.get(this.ApiH…

Python | 数据类型之列表

知识目录一、定义和遍历1.1 定义列表1.2 打印和截取列表1.3 遍历列表二、增删改查2.1 更新和删除列表2.3 脚本操作符 * in三、函数和方法3.1 函数3.2 方法列表是最常用的Python数据类型,它可以作为一个方括号内的逗号分隔值出现。列表的数据项不需要具有相同的类型…

springboot-rocketmq整合NOT_CONSUME_YET问题处理

一、测试流程1.添加POM<dependency><groupId>org.apache.rocketmq</groupId><artifactId>rocketmq-spring-boot-starter</artifactId><version>2.2.1</version></dependency>2.配置属性参数# 默认的消息组 rocketmq.producer.…

微信小程序项目初试总结

微信小程序项目初试总结准备工作注册小程序账号获取AppID下载 微信开发者工具下载 HBuilderX安装 scss/sass 编译HBuilderX 的调试新建项目把项目运行到微信开发者工具使用 Git 管理项目把项目托管到码云模块制作通用tabBar首页分类搜索商品列表商品详情加入购物车购物车页面登…

【手把手教你C#如何使用SqlSugar操作MySQL数据库】三 SqlSugar使用案例

SqlSugar 连接数据库、创建数据表、增删改查用法1.SqlSugar 连接MySQL数据库1.创建数据库2.创建库中的数据表3.数据的插入4.数据的查询5.数据更新6.数据保存7.数据删除2.整体案例脚本代码1.SqlSugar 连接MySQL数据库 1.创建数据库 using SqlSugar; public class DB : Singlet…

Word数据恢复,简单几个方法恢复未保存的Word文档!

日常生活中&#xff0c;我们经常会用到Word文档&#xff0c;里面记录着我们很多重要内容。当遇到电脑死机、没电关机&#xff0c;或者是编辑文档的软件突然崩溃&#xff0c;我们又没有及时保存Word文档里面的数据&#xff0c;这时该怎么办&#xff1f;Word数据恢复&#xff0c;…

[LeetCode]2319. 判断矩阵是否是一个 X 矩阵

如果一个正方形矩阵满足下述 全部 条件&#xff0c;则称之为一个 X 矩阵 &#xff1a; 矩阵对角线上的所有元素都 不是 0矩阵中所有其他元素都是 0 给你一个大小为 n x n 的二维整数数组 grid &#xff0c;表示一个正方形矩阵。如果 grid 是一个 X 矩阵 &#xff0c;返回 true…

VX拜年红包测试用例设计分享

功能测试 1.红包最多可以输入的金额&#xff1b;2.红包一次性可以发送的最大个数3.在输入红包的钱数和个数时只能输入数字4.当余额不足时&#xff0c;红包发送失败5.发送的红包自己是否可以领取6.发送的红包别人是否可以领取7.红包超过 24 小时是否可以领取8.红包超时未领取&a…

刑啊,为什么不刑

前言 你还在为使用浏览器的时候&#xff0c;忘记密码而烦恼吗&#xff1f;今天要分享的不为人知的小技巧&#xff0c;利用前端技术原理来帮助你找回原密码。 在我们使用各种网站登录时&#xff0c;总会勾选上记住密码这一项。 但长时间依赖记住密码&#xff0c;难免有遗忘的情…

CVE-2022-30331-TigerGraph 3.6.0 UDF 功能漏洞分析

TigerGraph UDF 漏洞&#xff1a;详细信息和示例 CVE 参考地址&#xff1a;http://www.cnnvd.org.cn/web/xxk/ldxqById.tag?CNNVDCNNVD-202209-215 TigerGraph 图数据库为用户提供了远程上传任意 C 源代码以创建用户定义函数的工具。该代码会自动编译并安装到敏感的系统组件中…

涨薪【20k】的python接口自动化系列文章(一)--什么是接口、接口优势、类型(详解)

简介 经常听别人说接口测试&#xff0c;接口测试自动化&#xff0c;但是你对接口&#xff0c;有多少了解和认识&#xff0c;知道什么是接口吗&#xff1f;它是用来做什么的&#xff0c;测试时候要注意什么&#xff1f;坦白的说&#xff0c;笔者之前也不是很清楚。接下来先看一下…

go 实现抓包 ,盗取浏览器接口信息|反反爬虫

项目地址 https://github.com/kxg3030/shermie-proxy 安装方法 如果有现有的项目可以可安装&#xff1a; go get github.com/kxg3030/shermie-proxy 尝试源码 git clone gitgithub.com:kxg3030/shermie-proxy.git 运行代码 克隆项目下来之后 安装依赖包 go mod tidy 运行程序…

详解注意力机制和Transformer

本文的学习路线&#xff1a; &#x1f4cd; Attention 从生物学的角度引入到计算机视角&#xff0c;介绍了什么是Attention ▶️介绍Encoder-Decoder框架 (目前大部分Attention Model都是依附于该框架实现)▶️ 介绍了Attention模型中的基础概念查询、键和值 ▶️ 通过讲解Nad…

地理坐标系,投影坐标系区别

目录1. 地球的三级逼近1.1 大地水准面1.2 旋转椭球体1.3 参考椭球体2. 地理坐标系&#xff08;大地坐标系&#xff09;2.1 大地基准面2.2 地理坐标系3. 投影坐标系参考1. 地球的三级逼近 1.1 大地水准面 概念 地球的自然状态下其表面并不是连续不断的&#xff0c;高山、悬崖的…

SpringBoot系列 整合MyBatis

数据源 <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.16</version> </dependency> yml spring: datasource: type: com.al…

C语言---插入排序(直接插入和希尔)

文章目录前言一、直接插入排序1.简介2.算法思路3.代码实现二、希尔排序1.简介2.算法思路3.代码实现前言 插入排序一般分为两种&#xff0c;一种直接插入排序&#xff0c;另一种则是希尔排序。 一、直接插入排序 1.简介 直接插入排序是一种简单的排序方法&#xff0c;基本操作…

每天一道大厂SQL题【Day02】电商场景TopK统计

每天一道大厂SQL题【Day02】 大家好&#xff0c;我是Maynor。相信大家和我一样&#xff0c;都有一个大厂梦&#xff0c;作为一名资深大数据选手&#xff0c;深知SQL重要性&#xff0c;接下来我准备用100天时间&#xff0c;基于大数据岗面试中的经典SQL题&#xff0c;以每日1题…

数据包络分析DEA(数学建模)

一、模型背景数据包络分析是线性规划模型的应用之一&#xff0c;常被用来衡量拥有相同目标的运营单位的相对效率。数据包络分析是一种基于线性规划的用于评价同类型组织(或项目&#xff09;工作绩效相对有效性的特殊工具手段。这类组织例如学校、医院、银行的分支机构、超市的各…

Qt QRegExp正则表达式

Qt QRegExp正则表达式 前言一、正则表达式是什么?二、元字符是什么?三、 常用表达式四、 在QT中的用法总结前言 在用写程序的时候,往往会用到正则表达式,不仅仅是Web开发,MFC、GTK+、Qt开发的图形界面也是如此,只要了解其原理,语法也都大相径庭! 一、正则表达式是什么…

java ssm智慧校园校医室问诊系统 idea maven

基于JSP技术、SSM框架、B/S机构、Mysql数据库设计并实现了智慧校园校医室问诊系统。系统主要包括个人中心、学生管理、校医管理、药品信息管理、校医科室管理、预检分诊管理、医生推荐管理、预约问诊管理、线上就诊管理、药方信息管理、药品购买管理、系统管理等功能模块。 通过…