C++之继承<2>【详解】
C++之继承<2>【详解】
- 1. 派生类的默认成员函数
- 1.1 1. 构造成员函数
- 1.2 拷贝复制
- 1.3 构造函数和析构函数的执行顺序
- 2. 继承和友元
- 3. 继承与静态成员
1. 派生类的默认成员函数
1.1 1. 构造成员函数
派生类的构造函数必须调用基类的构造函数初始化基类的那一部分成员。如果基类没有默认的构造函数,则必须在派生类构造函数的初始化列表阶段显示调用。
无论是否显示的调用基类的构造成员函数,都会自动调用基类的默认成员函数:
#include <iostream>
using namespace std;
class Person
{
public:Person(const char* name = "peter"): _name(name){cout << "Person()" << endl;}string _name;
};class Student : public Person
{
public:Student(const char* name, int num): _num(num){cout << "Student()" << endl;}
protected:int _num;
};
int main()
{Student s1("jack", 18);return 0;
}

显示调用后:

上述的后半段的意义是:如果基类没有默认的构造函数,那么是这样的:
Person(const char* name = "peter"): _name(name){}
可以进行传参来构造对象,如果你在派生类没有显示的调用它,那么不能进行进行传参来构造。
#include <iostream>
using namespace std;class Person
{
public:Person(const char* name = "peter"): _name(name){cout << "Person()" << endl;}string _name;
};class Student : public Person
{
public:Student(const char* name, int num): _num(num){cout << "Student()" << endl;}
protected:int _num;
};
int main()
{Student s1("jack", 18); cout << s1._name; return 0;
}

上图可以看到,传入的参数是“jack”, 但是构造出来的对象属性是“peter”。
至于必须在初始化列表显示的调用,是因为祖师爷定下的规则是,先构造基类再构造派生类,初始化列表是先于构造函数执行的。
Person(name)在初始化列表中的顺序可以随意改动的,因为初始化列表的执行顺序只跟声明的顺序有关,跟初始化列表中的先后顺序无关。
1.2 拷贝复制
分别是拷贝构造函数和operator=复制函数:
- 派生类的拷贝构造函数必须调用基类的拷贝构造完成基类的拷贝初始化。
- 派生类的operator=必须要调用基类的operator=完成基类的复制。
上面两条的原因和构造函数的一样,就不在赘述。
下面是验证的代码:
#include <iostream>
using namespace std;class Person
{
public:Person(const char* name = "peter"): _name(name){cout << "Person()" << endl;}Person(const Person& p): _name(p._name){cout << "Person(const Person& p)" << endl;}Person& operator=(const Person& p){cout << "Person operator=(const Person& p)" << endl;if (this != &p)//防止复制相同的对象,相同的就不必进行下面步骤了_name = p._name;return *this;}
protected:string _name; // 姓名
};class Student : public Person
{
public:Student(const char* name, int num): Person(name), _num(num){cout << "Student()" << endl;}Student(const Student& s): Person(s), _num(s._num){cout << "Student(const Student& s)" << endl;}Student& operator = (const Student& s){cout << "Student& operator= (const Student& s)" << endl;if (this != &s)//防止复制相同的对象,相同的就不必进行下面步骤了{Person::operator =(s);_num = s._num;}return *this;}
protected:int _num; //学号
};
int main()
{Student s1("jack", 18);Student s2(s1);return 0;
}
1.3 构造函数和析构函数的执行顺序
- 派生类的析构函数会在被调用完成后自动调用基类的析构函数清理基类成员。因为这样才能保证派生类对象先清理派生类成员再清理基类成员的顺序。
- 派生类对象初始化先调用基类构造再调派生类构造。
- 派生类对象析构清理先调用派生类析构再调基类的析构。
-
首先,为什么一定先调用基类构造函数再调用派生类的的构造函数呢?
如果你先调用派生类的构造函数,派生类是继承基类的,那么派生类中就可以使用基类中的属性和行为,但是此时还没有调用基类的构造函数,所以不能这样。 -
为什么一定先调用派生类的析构函数再调用基类的析构函数呢?
如果先调用基类的析构函数的话,会释放掉一些变量或指针,那么派生类使用继承过来的这些变量或者指针的时候,它们已经变成了野指针,因此不能如此。

下面是完整代码,大家可以尝试验证:
#include <iostream>
using namespace std;class Person
{
public:Person(const char* name = "peter"): _name(name){cout << "Person()" << endl;}Person(const Person& p): _name(p._name){cout << "Person(const Person& p)" << endl;}Person& operator=(const Person& p){cout << "Person operator=(const Person& p)" << endl;if (this != &p)_name = p._name;return *this;}~Person(){cout << "~Person()" << endl;}
protected:string _name; // 姓名
};class Student : public Person
{
public:Student(const char* name, int num): Person(name), _num(num){cout << "Student()" << endl;}Student(const Student& s): Person(s), _num(s._num){cout << "Student(const Student& s)" << endl;}Student& operator = (const Student& s){cout << "Student& operator= (const Student& s)" << endl;if (this != &s){Person::operator =(s);_num = s._num;}return *this;}~Student(){cout << "~Student()" << endl;}
protected:int _num; //学号
};
int main()
{Student s1("jack", 18);Student s2(s1);Student s3("rose", 17);s1 = s3;return 0;
}
2. 继承和友元
友元关系不能继承,也就是说基类友元不能访问子类私有和保护成员
#include <iostream>
using namespace std;class Student;
class Person
{
public:friend void Display(const Person& p, const Student& s);
protected:string _name = "zhangsan"; // 姓名
};class Student : public Person
{
public:protected:int _num; //学号
};void Display(const Person& p, const Student& s)
{cout << p._name << endl;cout << s._num << endl;
}
int main()
{Student s;Person p;Display(p, s);return 0;
}

从上面图中可以看出。
3. 继承与静态成员
基类定义了static静态成员,则整个继承体系里面只有一个这样的成员。无论派生出多少个子类,都只有一个static成员实例 。
#include <iostream>
#include <string>
using namespace std;class Person
{
public:Person(){++_count;++age;}public:static int _count;int age = 0; // 姓名
};
int Person::_count = 0;class Student : public Person
{
public:protected:int _num; //学号
};int main()
{Student s;Person p;cout << "Person::_count: "<<Person::_count<<endl;cout << "Person::age: "<<p.age<<endl;return 0;
}
运行结果是:

由此可见,静态成员_count是共有的,只有一个。
😄 创作不易,你的点赞和关注都是对我莫大的鼓励,再次感谢您的观看😄
相关文章:
C++之继承<2>【详解】
C之继承<2>【详解】 1. 派生类的默认成员函数1.1 1. 构造成员函数1.2 拷贝复制1.3 构造函数和析构函数的执行顺序 2. 继承和友元3. 继承与静态成员 1. 派生类的默认成员函数 1.1 1. 构造成员函数 派生类的构造函数必须调用基类的构造函数初始化基类的那…...
解决Kafka新消费者组导致重复消费的问题
问题描述:在使用Kafka时,当我们向新的消费者组中添加消费者时,可能会遇到重复消费的问题。本文将介绍一些解决这个问题的方法,帮助开发者更好地处理Kafka中的消费者组和消费偏移量。 Kafka是一个强大的分布式消息队列系统…...
公允价值会计(fair-value accounting)
《公允价值会计》是2008年经济科学出版社出版图书。 公允价值会计又称市值会计,是指以市场价值或未来现金流量的现值作为资产和负债的主要计量属性的会计模式。随着现代交通和通讯技术的发展,在工业社会中相互分割的市场正在走向世界一体化,…...
【java调取第三方接口,获取数据并保存至数据库】
java调取第三方接口,获取数据并保存至数据库 Overridepublic void doPost() {// 创建Httpclient对象CloseableHttpClient httpClient HttpClients.createDefault();CloseableHttpResponse response null;String resultString "";String url "htt…...
图论01-【无权无向】-图的基本表示-邻接矩阵/邻接表
文章目录 1. 代码仓库2. 图的基本表示的比较3. 邻接矩阵:Array和TreeSet3.1 图示3.2 Array主要代码解析3.3 测试输出3.4 使用TreeSet的代码 4. 邻接表:LinkedList4.1 图示4.2 LinkedList主要代码解析4.3 测试输出 5. 完整代码5.1 邻接表 - Array5.2 邻接…...
Bootstrap的列表组相关知识
目录 01-列表组的相关基础知识02-一个简单的列表组示例03-激活或禁用列表组的一行或多行04-设置列表项的颜色05-给列表项添加徽章 01-列表组的相关基础知识 Bootstrap的list-group是一个用于创建列表组件的CSS类,通常用于显示一个项目列表,如导航菜单或…...
Linux简单安装ffmpeg 实现用PHP压缩音频
一、下载安装 1、官方下载地址:Download FFmpeg 2、下载完上传到服务器然 然后解压就算安装完成了 tar -xf ffmpeg-git-amd64-static.tar.xz 3、然后配置一下全局变量(当然也可以不用配置 使用的时候带上文件路径就行) cd /usr/bin ln -s…...
Vue解决 npm -v 报错(一)
报错内容: npm WARN config global --global, --local are deprecated. Use --locationglobal instead. 解决方案: 代码: prefix -g 替换为: prefix --locationglobal 原创作者:吴小糖 创作时间:2023.1…...
IP地址是如何定位的
IP地址定位原理和方法 在互联网时代,了解设备或用户的地理位置对于各种应用和服务至关重要,从广告定向到网络安全。IP地址定位是一种常用的方法,允许确定IP地址背后的实际地理位置。本文将介绍IP地址定位的原理和方法。 IP地址基础…...
【分布式】入门级NCCL多机并行实践 - 02
# 背景知识 大模型和分布式训练对数据的吞吐量以及并行度都有很高的要求,NCCL就是在这个背景下诞生的。 如果你是一个只会写写Python,调用PyTorch和Horovod的算法萌新,可能对于分布式底层的东西不太了解,在下岗热潮中被主管逼着…...
Rust的模式匹配
文章目录 match匹配if let匹配 match匹配 match可以结合枚举使用,例如 enum IpVersion {V4,V6, }fn ParseIpVersion(version: IpVersion) -> String {match version {IpVersion::V4 > String::from("ipv4"),IpVersion::V6 > String::from(&quo…...
操作系统【OS】虚拟机
定义 使用虚拟化技术,将一台物理机器虚化为多台虚拟机器VM,每个虚拟机器都可用独立运行一个操作系统 分类 传统计算机 第一类VMM 第二类VMM...
不写代码、构建一个开源的 ChatGPT,总共需要几步?|Hugging News #1020
每一周,我们的同事都会向社区的成员们发布一些关于 Hugging Face 相关的更新,包括我们的产品和平台更新、社区活动、学习资源和内容更新、开源库和模型更新等,我们将其称之为「Hugging News」。本期 Hugging News 有哪些有趣的消息࿰…...
VBA操作数据库
相关背景: 对于数据分析同学,一般SQL,EXCEL是必备技能,但对于VBA和Python可能有的同学不会;在处理本地数据上(诸如excel、txt|csv文本),后续尝试使用VBA或者Python写一个sql查询的GUI界面&…...
【华为OD机试】HJ26 字符串排序
描述 编写一个程序,将输入字符串中的字符按如下规则排序。 规则 1 :英文字母从 A 到 Z 排列,不区分大小写。 如,输入: Type 输出: epTy 规则 2 :同一个英文字母的大小写同时存在时,…...
哈里斯鹰算法优化BP神经网络(HHO-BP)回归预测研究(Matlab代码实现)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...
摆动序列【贪心4】
题目 分析 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {if(nums.size() < 2) return nums.size();int ret 0,left 0,right 0;for(int i 0;i < nums.size()-1;i){right nums[i1] - nums[i];if(right 0) continue;if(left …...
Youtrack Linux 安装
我们考虑最后应该使用的是 ZIP 方式的安装。 按照官方的说法如何设置运行 YouTrack 应该是非常简单的。 准备环境 根据官方的说法,我们需要做的就是下载 Zip 包,然后把 Zip 包解压到指定的目录中就可以了。 下载 当前官方的下载地址为:Ge…...
分类预测 | MATLAB实现SSA-CNN-LSTM麻雀算法优化卷积长短期记忆神经网络数据分类预测
分类预测 | MATLAB实现SSA-CNN-LSTM麻雀算法优化卷积长短期记忆神经网络数据分类预测 目录 分类预测 | MATLAB实现SSA-CNN-LSTM麻雀算法优化卷积长短期记忆神经网络数据分类预测分类效果基本描述程序设计参考资料 分类效果 基本描述 1.MATLAB实现SSA-CNN-LSTM数据分类预测&…...
飞书-多维文档-计算时间差
1. 选择字段类型 如图所示,字段类型选择 公式 2. 编辑公式 单击 公式编辑器 在弹出的公式编辑框中输入公式 TEXT([终结时间]-[开始时间],"HH:MM") [终结时间] 和 [开始时间] 请替换成你的表格中对应的字段名称HH:MM 表示输出的时间格式为 时:分其中 “…...
19c补丁后oracle属主变化,导致不能识别磁盘组
补丁后服务器重启,数据库再次无法启动 ORA01017: invalid username/password; logon denied Oracle 19c 在打上 19.23 或以上补丁版本后,存在与用户组权限相关的问题。具体表现为,Oracle 实例的运行用户(oracle)和集…...
云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?
大家好,欢迎来到《云原生核心技术》系列的第七篇! 在上一篇,我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在,我们就像一个拥有了一块崭新数字土地的农场主,是时…...
智慧医疗能源事业线深度画像分析(上)
引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...
解决本地部署 SmolVLM2 大语言模型运行 flash-attn 报错
出现的问题 安装 flash-attn 会一直卡在 build 那一步或者运行报错 解决办法 是因为你安装的 flash-attn 版本没有对应上,所以报错,到 https://github.com/Dao-AILab/flash-attention/releases 下载对应版本,cu、torch、cp 的版本一定要对…...
让回归模型不再被异常值“带跑偏“,MSE和Cauchy损失函数在噪声数据环境下的实战对比
在机器学习的回归分析中,损失函数的选择对模型性能具有决定性影响。均方误差(MSE)作为经典的损失函数,在处理干净数据时表现优异,但在面对包含异常值的噪声数据时,其对大误差的二次惩罚机制往往导致模型参数…...
AI病理诊断七剑下天山,医疗未来触手可及
一、病理诊断困局:刀尖上的医学艺术 1.1 金标准背后的隐痛 病理诊断被誉为"诊断的诊断",医生需通过显微镜观察组织切片,在细胞迷宫中捕捉癌变信号。某省病理质控报告显示,基层医院误诊率达12%-15%,专家会诊…...
Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习)
Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习) 一、Aspose.PDF 简介二、说明(⚠️仅供学习与研究使用)三、技术流程总览四、准备工作1. 下载 Jar 包2. Maven 项目依赖配置 五、字节码修改实现代码&#…...
Selenium常用函数介绍
目录 一,元素定位 1.1 cssSeector 1.2 xpath 二,操作测试对象 三,窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四,弹窗 五,等待 六,导航 七,文件上传 …...
【LeetCode】算法详解#6 ---除自身以外数组的乘积
1.题目介绍 给定一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法,且在 O…...
学习一下用鸿蒙DevEco Studio HarmonyOS5实现百度地图
在鸿蒙(HarmonyOS5)中集成百度地图,可以通过以下步骤和技术方案实现。结合鸿蒙的分布式能力和百度地图的API,可以构建跨设备的定位、导航和地图展示功能。 1. 鸿蒙环境准备 开发工具:下载安装 De…...
