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

C++相关概念和易错语法(19)(继承规则、继承下的构造和析构、函数隐藏)

1.继承规则

继承的本质是复用,是结构上的继承而不是内容上的继承,近似于在子类中声明了父类的成员变量。

(1)写法:class student : public person
     派生类(子类),继承方式,基类(父类) 

它们都分public、protected、private三种,但是含义并不相同。

(2)区分访问限定符和继承方式

访问限定符修饰的是在当前类里面是否可以访问,而继承方式是指在继承的类里面的访问方式,并且一个成员继承后的访问限定符是父类的访问限制符和子类继承方式两者间的较小权限如果A有public成员a,而以protectd继承,因此子类成员的访问限制符是protected。

访问权限由大到小是public>protected>private,protected和private在继承语法外没有区别。比如protected成员public继承后是protected,protected成员private继承后是private,public成员public继承后是public,这都非常容易理解。


#include <iostream>
using namespace std;class A
{
public:int _a = 0;
protected:int _b = 1;
private:int _c = 2;
};class B : public A
{
public:void GetNum(){cout << _a << " " << _b  << " " << _d << endl;}int _d = 3;
};int main()
{B().GetNum();return 0;
}

但是要注意private成员无论以何种方式继承,不管是public、protected还是private继承,最终子类成员的访问权限都是private且这个private成员不能被子类使用(包括访问,修改等)

看起来这个成员没有被继承,但实际上子类包含该成员。我们可以从监视窗口和类的大小双重验证这个结论。

(3)在继承里还规定友元关系不能继承,父类的友元不是子类的友元,只有子类自己声明友元

(4)形象理解:父的成员是protected意味着这些成员对外是个秘密,但在自己家庭中不算个秘密,但家庭中的每个人都有义务对外保守这个秘密,即protected无论以何种方式继承对外都不可见。

如果父成员有个private意味着这个成员是自己的秘密,不能给任何人说,比如家里有个隐藏的地下室。但是在继承给自己孩子这个房子时,孩子不知有这个地下室,但这个地下室真实存在,即private无论以何种方式继承对子对外均不可见,但这个private成员真实存在。

父的朋友不是子的朋友,即友元关系不能继承。

(5)protected和private区分

protected在继承以后才有意义。protected和private对外的功能都一样,都是不可见,它们区别在protected对整个继承体系开放(前提没有子类以private继承它),而private是只有该类能访问,其子类也不能访问。

当中途被继承为private后,对子该成员依然不可见。

(6)默认继承方式

我们也可以选择不写继承方式,这个时候class默认私有继承,struct默认以public继承,注意这和默认访问限定符一样,但这是两个概念。

2.继承的函数调用

我们先尝试解读下面的代码,这能帮助我们初步理解继承函数调用的特征:


#include <iostream>
using namespace std;class A
{
public:A(int a, int b, int c):_a(a),_b(b),_c(c){}void GetNum(){printf("%d %d %d\n", _a, _b, _c);}int _a = 0;
protected:int _b = 1;
private:int _c = 2;
};class B : public A
{
public:B():A(7, 8, 9), _d(5){}void GetNum(){printf("%d\n", _d);}int _d = 3;
};int main()
{B().A::GetNum();B().GetNum();return 0;
}

结果是

(1)构造函数

A作为父类它的构造函数正常写就是了,我们重点关注B的构造函数。

我们知道,构造函数实际构造的顺序是声明的顺序而非初始化列表的顺序。这里我们可以理解为B子类的第一个成员声明是匿名的A,在初始化时要根据A的构造函数把A当作一个整体用匿名初始化对象的方式A(7,8,9)来处理,不能直接对A的成员变量直接初始化继承的A对象和创建一个A对象一样都不会复制函数和static变量,在需要时都是直接去A里面取,即整个继承体系共享一套函数和static变量

(2)函数的隐藏

在继承体系中是允许出现同名函数的,但是这并不构成函数重载,因为函数重载的前提是必须在同一个作用域定义两个同名函数,而这里很明显是在两个类域里定义的同名函数,所以一定不构成重载,而是构成函数的隐藏(只需要同名就构成隐藏了,要和后面的多态区分开)。

如果构成了函数隐藏的话,应该怎么区分调用这两个函数呢?很多人会以为能像函数重载的调用那样根据参数匹配程度来调用,但这个逻辑在继承里走不通,万一我就想利用隐式类型转换调用子的成员函数,但是参数却匹配了父的成员函数呢?万一是我参数写错了导致匹配错误的情况呢?这些问题都会导致歧义的发生。所以规定,只要构成函数隐藏,调用父类一定要指明类域,调用当前类的不用指明,如果不指明类域,一律只按调用当前类的函数来处理,就算此时调用匹配父类的函数参数。

我们这里还可以学到,虽然我们不能直接访问父类的私有成员_c == 9,但是我们可以选择调用父类的非private和protected函数,从而达到间接访问的目的。

(3)析构函数与构造函数

析构函数的理解相对复杂,我们先看一下下面的代码,这能帮助我们深入理解构造和析构函数:


#include <iostream>
using namespace std;class A
{
public:~A(){delete _a;}int* _a = new int(1);
};class B : public A
{
public:B():_b(_a){}~B(){A::~A();*_b = 2;}int* _b;
};int main()
{B a;return 0;
}

结果是报错,接下来我会详细分析里面的代码

为什么写作A::~A();

析构函数的名字会被统一处理为destructor(),父子类的析构函数同名构成了函数隐藏,因此想要调用父的析构函数,就必须要指定类域,这个底层细节需要我们记住。这个特殊处理的原因在多态我会提及。

为什么报错?

由于在父类的析构函数调用后间接使用了父类的成员,所以出现越界访问的情况。

我们还能发现B的构造函数借助了A的成员变量。这里要区分开的是,在子类初始化父类时只能以父类为整体去调用它的构造函数如A(7,8,9),而本质上继承的只是它的成员变量,在子类的构造函数中可以直接用父类的成员。

如此一来,我们能发现,子类的构造函数可能会依靠父类的成员变量,若父类先析构,那在子类需要用到父类成员变量时就可能会发生越界访问。所以规定,父类的构造函数一定先于子类,父类的析构一定晚于子类(构造先父后子,析构先子后父)。

在实现层面上,由于子类的第一个成员变量默认是父类A,所以我们可以不用关心,毕竟初始化顺序是按声明而不是初始化列表。但是我们要避免显式地调用父类的析构,即A::~A()不要出现在我们的继承代码中。当子类的析构函数走完后,会去自动调用父类的析构。同理,如果没有显式写构造,编译器也会首先自动调用父类的默认构造。

相关文章:

C++相关概念和易错语法(19)(继承规则、继承下的构造和析构、函数隐藏)

1.继承规则 继承的本质是复用&#xff0c;是结构上的继承而不是内容上的继承&#xff0c;近似于在子类中声明了父类的成员变量。 &#xff08;1&#xff09;写法&#xff1a;class student : public person 派生类&#xff08;子类&#xff09;&#xff0c;继承方式&…...

使用GPT-4和ChatGPT构建应用项目

文章目录 项目1:构建新闻稿生成器项目2:YouTube视频摘要项目3:打造《塞尔达传说:旷野之息》专家项目4:语音控制项目1:构建新闻稿生成器 GPT-4和ChatGPT等LLM专用于生成文本。我们可以使用GPT-4和ChatGPT在各种场景中生成文本,举例如下。 电子邮件合同或正式文档创意写作…...

mobx学习笔记

mobx介绍 mobx是一个功能强大&#xff0c;上手容易的状态管理工具。MobX背后的哲学很简单:任何源自应用状态的东西都应该自动地获得。利用getter和setter来收集组件的数据依赖关系&#xff0c;从而在数据发生变化的时候精确知道哪些组件需要重绘。 mobx和redux的区别 mobx更…...

深入理解 Cowboy WebSocket:使用 Erlang/OTP 构建高效的即时通讯(IM)应用

深入理解 Cowboy WebSocket&#xff1a;使用 Erlang/OTP 构建高效的即时通讯(IM)应用 引言 实时通信技术在现代 Web 应用中扮演着核心角色&#xff0c;而 WebSocket 作为其中的关键技术&#xff0c;已成为即时通讯(IM)系统不可或缺的一部分。Cowboy&#xff0c;这个基于 Erla…...

算法的几种常见形式

算法&#xff08;Algorithm&#xff09; 算法&#xff08;Algorithm&#xff09;是指解决问题或完成任务的一系列明确的步骤或规则。在计算机科学中&#xff0c;算法是程序的核心部分&#xff0c;它定义了如何执行特定的任务或解决特定的问题。算法可以用多种方式来表示和实现…...

SpringBoot新手快速入门系列教程二:MySql5.7.44的免安装版本下载和配置,以及简单的Mysql生存指令指南。

我的教程都是亲自测试可行才发布的&#xff0c;如果有任何问题欢迎留言或者来群里我每天都会解答。 我们要如何选择MySql 目前主流的Mysql有5.0、8.0、9.0 主要区别 MySQL 5.0 发布年份&#xff1a;2005年特性&#xff1a; 基础事务支持存储过程、触发器、视图基础存储引擎…...

Elasticsearch 更新指定字段

Elasticsearch 更新指定字段 准备条件查询数据更新指定字段更新子级字段 准备条件 以下查询操作都基于索引crm_clue来操作&#xff0c;索引已经建过了&#xff0c;本文主要讲Elasticsearch更新指定字段语句&#xff0c;下面开始写更新语句执行更新啦&#xff01; 查询数据 查…...

Koa.js、Egg.js与Express.js:探析三大Node.js框架的异同

在Node.js的世界里&#xff0c;选择合适的框架对于构建高效、可维护的后端服务至关重要。Express.js、Koa.js 和 Egg.js 是三个备受欢迎的框架&#xff0c;它们各有特色&#xff0c;适用于不同的开发场景。本文旨在深入探讨这三个框架的区别&#xff0c;并通过代码示例帮助开发…...

【MYSQL】如何解决 bin log 与 redo log 的一致性问题

该问题问的其实就是redo log 的两阶段提交 为什么说redo log 具有崩溃恢复的能力 MySQL Server 层拥有的 bin log 只能用于归档&#xff0c;不足以实现崩溃恢复&#xff08;crash-safe&#xff09;&#xff0c;需要借助 InnoDB 引擎的 redo log 才能拥有崩溃恢复的能力。所谓崩…...

翻译语音识别在线的软件,分享4款实用的软件!

在全球化日益加速的今天&#xff0c;语言沟通已成为人们生活中不可或缺的一部分。无论是商务洽谈、学术交流还是日常交流&#xff0c;翻译语音识别技术都扮演着举足轻重的角色。今天&#xff0c;我们就来揭秘一下&#xff0c;那些能让你在语言沟通中如虎添翼的翻译语音识别软件…...

Qt 的Q_PROPERTY关键字

Qt 的Q_PROPERTY关键字 1. Q_PROPERTY 的由来2. 实现原理3. Q_PROPERTY 的特点4. Q_PROPERTY 的属性5. 应用说明示例代码示例代码连接信号和槽的多种方式处理信号和槽的注意事项 QT的元对象系统1. 元对象系统的由来2. 实现原理3. 元对象系统的特点4. 元对象系统的属性5. 应用说…...

github 下载提速的几种方法

1. 代理下载&#xff08;无需注册&#xff09; //toolwa.com/github/ //d.serctl.com/2. 转入 Gitee 加速 将项目镜像到 Gitee 中下载加速 3. 使用 Watt Toolkit 加速 Watt Toolkit //steampp.net/选择合适的版本下载 选择 github&#xff0c;一键加速 4.CDN 加速 (修改…...

【Oracle】实验三 Oracle数据库的创建和管理

【实验目的】 掌握Oracle数据库的创建方法使用DBCA创建数据库在数据库中装入SCOTT用户及其表 【实验内容】 使用DBCA创建数据库&#xff0c;名为MYDB&#xff0c;找到其初始化文件(文本型和服务器型文件都要找到)&#xff0c;查看各类默认位置并记录下来(包括物理文件所在目…...

Linux rpm和ssh损坏修复

背景介绍 我遇到的问题可能和你的不一样。但是如果遇到错误一样也可以按此方案尝试修复。 我是想在Linux上安装Oracle&#xff0c;因为必须在离线环境下安装。就在网上搜一篇文章linux离线安装oracle&#xff0c;然后安装教程走&#xff0c;进行到安装oracle依赖包的时候执行了…...

仕考网:公务员考试面试时间一般多长?

公务员考试主要分为笔试与面试两个阶段&#xff0c;其中面试是笔试通过的下一关&#xff0c;面试的具体安排通常由相关考试机构或招录单位负责发布并通知考生。 公务员面试的持续时间一般在30分钟至1小时之间&#xff0c;具体时长可能因地区和招录单位的不同而有所变化。常见的…...

C语言作业5(学生管理系统C语言)

成学生管理系统 1> 使用菜单完成 2> 有学生的信息录入功能&#xff1a;输入学生个数&#xff0c;并将学生的姓名、分数录入 3> 查看学生信息&#xff1a;输出所有学生姓名以及对应的分数 4> 求出学习最好的学生信息&#xff1a;求最大值 5> 按姓名将所有学…...

OS Copilot:新手测评体验

文章目录 前言一、OS Copilot&#xff08;阿里云操作系统智能助手&#xff09;简介二、测评体验总结OS Copilot 产品体验评测OS Copilot 产品功能反馈 前言 本文简单分享一下自己使用OS Copilot测评体验。 一、OS Copilot&#xff08;阿里云操作系统智能助手&#xff09;简介 …...

PS 2024【最新】中文白嫖版!,安装教程,图文步骤

文章目录 软件介绍软件下载安装步骤 软件介绍 Photoshop&#xff0c;简称“PS” Adobe Photoshop&#xff0c;简称“PS”&#xff0c;是由Adobe Systems开发和发行的图像处理软件。Photoshop主要处理以像素所构成的数字图像。使用其众多的编修与绘图工具&#xff0c;可以有效地…...

bind方法的使用

在JavaScript或TypeScript中&#xff0c;this.data.setEventListener(this.onAddEvent.bind(this)); 和 this.data.setEventListener(this.onAddEvent); 之间的主要区别在于this关键字的绑定方式。 不使用.bind(this) 当你直接传递函数引用 this.onAddEvent给 setEventListene…...

MySQL数据库基本操作-DDL和DML

1. DDL解释 DDL(Data Definition Language)&#xff0c;数据定义语言&#xff0c;该语言部分包括以下内容&#xff1a; 对数据库的常用操作对表结构的常用操作修改表结构 2. 对数据库的常用操作 功能SQL查看所有的数据库show databases&#xff1b;查看有印象的数据库show d…...

label-studio的使用教程(导入本地路径)

文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...

DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径

目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...

VB.net复制Ntag213卡写入UID

本示例使用的发卡器&#xff1a;https://item.taobao.com/item.htm?ftt&id615391857885 一、读取旧Ntag卡的UID和数据 Private Sub Button15_Click(sender As Object, e As EventArgs) Handles Button15.Click轻松读卡技术支持:网站:Dim i, j As IntegerDim cardidhex, …...

Redis相关知识总结(缓存雪崩,缓存穿透,缓存击穿,Redis实现分布式锁,如何保持数据库和缓存一致)

文章目录 1.什么是Redis&#xff1f;2.为什么要使用redis作为mysql的缓存&#xff1f;3.什么是缓存雪崩、缓存穿透、缓存击穿&#xff1f;3.1缓存雪崩3.1.1 大量缓存同时过期3.1.2 Redis宕机 3.2 缓存击穿3.3 缓存穿透3.4 总结 4. 数据库和缓存如何保持一致性5. Redis实现分布式…...

Python爬虫实战:研究feedparser库相关技术

1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的信息资源。RSS(Really Simple Syndication)作为一种标准化的信息聚合技术,被广泛用于网站内容的发布和订阅。通过 RSS,用户可以方便地获取网站更新的内容,而无需频繁访问各个网站。 然而,互联网…...

大数据零基础学习day1之环境准备和大数据初步理解

学习大数据会使用到多台Linux服务器。 一、环境准备 1、VMware 基于VMware构建Linux虚拟机 是大数据从业者或者IT从业者的必备技能之一也是成本低廉的方案 所以VMware虚拟机方案是必须要学习的。 &#xff08;1&#xff09;设置网关 打开VMware虚拟机&#xff0c;点击编辑…...

Go 语言接口详解

Go 语言接口详解 核心概念 接口定义 在 Go 语言中&#xff0c;接口是一种抽象类型&#xff0c;它定义了一组方法的集合&#xff1a; // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的&#xff1a; // 矩形结构体…...

解决本地部署 SmolVLM2 大语言模型运行 flash-attn 报错

出现的问题 安装 flash-attn 会一直卡在 build 那一步或者运行报错 解决办法 是因为你安装的 flash-attn 版本没有对应上&#xff0c;所以报错&#xff0c;到 https://github.com/Dao-AILab/flash-attention/releases 下载对应版本&#xff0c;cu、torch、cp 的版本一定要对…...

土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等

&#x1f50d; 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术&#xff0c;可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势&#xff0c;还能有效评价重大生态工程…...

自然语言处理——循环神经网络

自然语言处理——循环神经网络 循环神经网络应用到基于机器学习的自然语言处理任务序列到类别同步的序列到序列模式异步的序列到序列模式 参数学习和长程依赖问题基于门控的循环神经网络门控循环单元&#xff08;GRU&#xff09;长短期记忆神经网络&#xff08;LSTM&#xff09…...