C++——继承

文章目录
- 🦜1. 什么是继承
- 🐊1.1 概念
- 🐊1.2 格式
- 🐊1.3 继承方式 & 访问限定符
- 🐦2. 派生类和基类的赋值问题
- 🦩3. 派生类和基类同名成员问题
- 🐓4.派生类默认成员函数
- 🐉4.1 构造函数
- 🐉4.2 拷贝构造
- 🐉4.3 赋值运算符重载
- 🐉4.4 析构函数
- 🐥5. 友元和静态成员
- 🐧6. 多继承
🦜1. 什么是继承
🐊1.1 概念
在现实生活中,谈起继承,就会联想到继承家业、家产。
而在编程世界中,继承也是如此,一个类(称子类或者派生类),可以继承另一个类(称父类或基类)的属性和行为。
//定义一个人的属性 基类
class Person
{
public:Person(string name = "Kangkang", string gender = "male", int age = 18):_name(name),_gender(gender),_age(age){cout << "Person()" << endl;}void Print(){cout << "name:" << _name << endl;cout << "gender:" << _gender << endl;cout << "age:" << _age << endl;}
protected:string _name; // 姓名string _gender; // 姓别int _age; //年龄
};
//定义一个学生类,继承人的属性 子类
class Student :public Person
{
public:Student(string name = "Lihua", string gender = "female", int age = 20, int id=111):Person(name,gender,age),_stuId(id){};
protected:int _stuId; //学号
};
int main()
{Person p;Student stu("Lisa","female",20,20230812);p.Print();stu.Print();return 0;
}
🐊1.2 格式
class 子类 : 继承方式 基类
{};

🐊1.3 继承方式 & 访问限定符

| 继承方式 | public继承 | protected继承 | private继承 |
|---|---|---|---|
| 父类public成员 | 子类的public成员 | 子类的protected成员 | 子类的private成员 |
| 父类的protected成员 | 子类的protected成员 | 子类的protected成员 | 子类的private成员 |
| 父类的private成员 | 子类不可见 | 子类不可见 | 子类不可见 |
这里其实很好分辨,我们只需要取权限小的即可:public>protected>private
对于public成员,我们可以直接在类的外面访问调用,而对于protected成员,可在类里面通过this指针访问,而private成员,虽然继承到了派生类对象中,但无法访问到,也可以理解为将父类的成员设为private就是不想让其他类继承

但是在实际应用过程中,一般都是采用的public继承方式
Tips:
关键字
class不指定继承方式时,默认继承方式为private而使用
struct关键字时,默认继承方式为public但这里还是建议,每次都显示继承方式
class A
{
public:void func1() { cout << "func1()" << endl; }
protected:void func2(){ cout << "func2()" << endl; }
private:void func3(){ cout << "func3()" << endl; }int _a = 0;
};
class B :public A
{
public:void Print(){this->func1();this->func2();}int _b = 1;};
int main()
{B b;b.Print();
}
🐦2. 派生类和基类的赋值问题
派生类和基类之间的赋值操作涉及到对象切片的问题。派生类的对象可以赋值给基类对象/基类指针/基类引用 ,但反过来(将基类对象赋值给派生类对象)是不合法的,因为这可能导致对象切片,即派生类对象的额外成员信息丢失

这就好比,学习C++,C++是在C语言的基础上衍生出来的,可以理解问C++继承了C语言的衣钵,C++的代码可以兼容C的代码;反之,C的代码却不能却不能兼容C++。

🦩3. 派生类和基类同名成员问题
class A
{
public:int _x=1;int _y=2;void Print(){cout << "A()" << endl;}
};
class B :public A
{
public:int _x = 3;int _y = 4;void Print(){cout << "B()" << endl;}
};
int main()
{B b;cout << b._x << endl; // 3cout << b._y << endl; // 4b.Print(); // B()
}
这段代码基类A和派生类B,成员名都是相同的,但我们输出发现,输出的是派生类的成员,那这里是否继承了A的这些成员呢?

通过监视窗口发现,这里A是被B继承了,但是由于成员名相同,A被B给隐藏了,这也叫重定义。
如果要访问基类的成员,可使用基类:基类成员显示访问,这也可理解问他们都有着独立的作用域

🐓4.派生类默认成员函数
🐉4.1 构造函数
派生类的构造函数必须调用基类的构造函数来初始化继承下来的那部分成员;如果基类没有默认构造,那在派生类构造函数的初始化列表显示调用
class Person
{
public://全缺省,默认构造Person(string name = "Kangkang"):_name(name){}
protected:string _name;
};
class Student : public Person
{
public:Student(string name, int id):Person(name),_id(id){}void Print(){cout << "name:" << _name << endl;cout << "id:" << _id << endl;}
protected:int _id;
};
int main()
{Student stu("Lisa",2023);stu.Print();return 0;
}
🐉4.2 拷贝构造
派生类的拷贝构造函数必须调用基类的拷贝构造完成基类的拷贝初始化,但我们可以直接传子类对象,因为调用父类的拷贝构造时,父类会自动切片拿到父类中的对象
父类拷贝构造
Person(const Person& p):_name(p._name)
{}
子类拷贝构造
Student(const Student&stu):Person(stu._name),_id(stu._id)
{}
调用
Student stu("Lisa", 2023);
stu.Print();
Student stu2(stu);
stu2.Print();
🐉4.3 赋值运算符重载
子类的operator=必须要调用父类的operator=完成基类的复制;但是因为赋值运算符重载了=,那么子类和父类的名字都是一样,这样就造成了子类隐藏了父类的operator=。所以需要显示调用父类的operator=
//operator=
Person& operator=(const Person& p)
{if (this != &p){_name = p._name;}return *this;
}
Student& operator=(Student& stu)
{if (this != &stu){//指定调用父类Person::operator =(stu);_id = stu._id;}return *this;
}
🐉4.4 析构函数
子类的析构函数会在被调用完成后自动调用父类的析构函数清理基类成员;因为这样才能保证子类对象先清理子类成员再清理父类成员的顺序。
Tips:
切记,这里是自动调用父类的析构,所以我们不需要在子类的析构函数中调用父类的析构函数
如果这里有指针,同一块区域释放两次,会造成未定义行为
🐥5. 友元和静态成员
在继承中,友元关系是不可以被继承的,就好比咱们朋友的朋友,不一定是咱们的朋友。
对于静态成员,这里继承的是它的使用权,就比如家里有三个孩子,一个大哥哥,两个小弟弟,这个哥哥是他两“共用的”,并不会说2个弟弟必须有2个哥哥。
class A
{
public:static int _sa;int _a;
};
int A::_sa = 1;
class B :public A
{
public:int _b;
};int main()
{A a;B b;cout <<"a._a:" << &a._a << endl;cout <<"b._a:" << &b._a << endl;cout <<"a._sa:" << &A::_sa << endl;cout <<"b._sa:" << &B::_sa<< endl;
}
这里也可以验证,对于静态成员,父类和子类是共用的(可用于计算父类有多少个派生类)。
🐧6. 多继承
对于一个子类只有一个直接父类,这种关系称为单继承
//单继承
class A
{};
class B:public A
{};
class C :public B
{};
而对于一个子类有多个直接父类,这种关系称为多继承
//多继承
class A
{};
class B
{};
class C :public A, public B
{};
多继承会引发一个很麻烦的问题——菱形继承

我们先来上代码
class A
{
public:int _a;
};
class B:public A
{
public:int _b;
};
class C :public A
{
public:int _c;
};
class D :public B, public C
{
public:int _d;
};
int main()
{D d;d._a = 1; //errord._b = 2;return 0;
}
这段代码,直接报错,_a的指定不明确,因为D类继承了B类和C类,编译器不知道这个_a是属于继承的哪个类,从而产生二义性的问题。

当然,前面也提到过,可以通过指定类域,来明确告诉编译器,这属于哪个类
D d;
d.B::_a = 1;
d.C::_a = 2;
d._b = 3;
d._c = 4;
d._d = 5;
这样虽然解决了二义性的问题,但是这样看的数据十分冗余,很容易分不清哪个是哪个

为了填补这个坑,推出了一种名为虚拟继承的继承方式(仅限菱形继承使用,其他地方不要使用)
class A
{
public:int _a;
};
class B:virtual public A
{
public:int _b;
};
class C :virtual public A
{
public:int _c;
};
class D :public B, public C
{
public:int _d;
};
int main()
{D d;d.B::_a = 1;d.C::_a = 2;d._b = 3;d._c = 4;d._d = 5;d._a = 6;return 0;
}
使用虚拟继承之后,我们发现这里的_a,只有一份了,而且我们查看内存发现,数据并不是连在一起,多了一些地址

这叫做虚基表,用来寻找基类偏移量的表,虚拟继承的派生类里面就包含了这个虚表,这个虚表记录着距离基类的偏移量,如果要用到基类的数据,加上这个距离就能找到,这样就解决了数据的二义性和数据冗余的问题。
但是在实际过程中,这个模型十分鸡肋且复杂,所以一般都不会采用这种继承方式。
多继承就属于C++语法复杂的一个体现,而继承虽然可以复用,但是继承的耦合度十分高,代码直接的依赖关系很强,这样就造成了代码的不便于维护。但又涉及到多态必须使用继承,所以在实际之中,代码要复用的话,我们得分场景。
那本期的方向就到这咯,我们下期再见,如果有下期的话。
相关文章:
C++——继承
文章目录 🦜1. 什么是继承🐊1.1 概念🐊1.2 格式🐊1.3 继承方式 & 访问限定符 🐦2. 派生类和基类的赋值问题🦩3. 派生类和基类同名成员问题🐓4.派生类默认成员函数🐉4.1 构造函数…...
openGauss学习笔记-38 openGauss 高级数据管理-游标
文章目录 openGauss学习笔记-38 openGauss 高级数据管理-游标38.1 语法格式38.2 参数说明38.3 示例 openGauss学习笔记-38 openGauss 高级数据管理-游标 为了处理SQL语句,存储过程进程分配一段内存区域来保存上下文联系。游标是指向上下文区域的句柄或指针。借助游…...
Blazor简单教程(1.1):Razor基础语法
文章目录 前言基本文件配置引入Layout组件 语法介绍pagecodeRazor 语法[ 显式表达和隐式表达](https://learn.microsoft.com/zh-cn/aspnet/core/mvc/views/razor?viewaspnetcore-7.0#explicit-razor-expressions) 绑定简单绑定双向绑定带参数的函数绑定 依赖注入 前言 Blazor…...
Leetcode-每日一题【剑指 Offer 25. 合并两个排序的链表】
题目 输入两个递增排序的链表,合并这两个链表并使新链表中的节点仍然是递增排序的。 示例1: 输入:1->2->4, 1->3->4输出:1->1->2->3->4->4 限制: 0 < 链表长度 < 1000 解题思路 1…...
前端盒子模型
day05-盒子模型 目标:掌握盒子模型组成部分,使用盒子模型布局网页区域 01-选择器 结构伪类选择器 基本使用 作用:根据元素的结构关系查找元素。 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lNhfXFEc-169194…...
【ARM Cache 系列文章 9 -- ARM big.LITTLE技术】
文章目录 big.LITTLE 技术背景big.LITTLE 技术详解big.LITTLE 硬件要求 big.LITTLE 软件模型CPU MigrationGlobal Task SchedulingGlobal Task Scheduling比CPU Migration的优势 转自:https://zhuanlan.zhihu.com/p/630981648 如有侵权,请联系删除 big.L…...
【BASH】回顾与知识点梳理(十四)
【BASH】回顾与知识点梳理 十四 十四. 文件与目录的默认权限与隐藏权限14.1 文件预设权限:umaskumask 的利用与重要性:专题制作 14.2 文件隐藏属性chattr (配置文件案隐藏属性)lsattr (显示文件隐藏属性) 14.3 文件特殊权限: SUID, SGID, SBI…...
乡村振兴指数与其30余个原始变量数据(2000-2022年)
乡村振兴是当下经济学研究的热点之一,对乡村振兴进行测度,是研究基础。测度乡村振兴水平的学术论文广泛发表在《数量经济技术经济研究》等顶刊上。整理了2000-2022年城市层面的乡村振兴指数与其30余个原始变量数据,供大家使用。 数据来源&…...
深入理解MySQL表的操作和管理
MySQL是一种广泛使用的关系型数据库管理系统,用于存储和管理大量结构化数据。在MySQL中,表是数据的基本组织单位,对表的操作和管理能力对于数据库的性能和数据完整性至关重要。本文将深入讨论MySQL表的操作和管理,包括创建表、修改…...
MATLAB图论合集(一)基本操作基础
本帖总结一些经典的图论问题,通过MATLAB如何计算答案。近期在复习考研,以此来巩固一下相关知识——虽然考研肯定不能用MATLAB代码哈哈,不过在实际应用中解决问题还是很不错的,比C易上手得多~ 图论中的图(Graph…...
Redis布隆过滤器的原理和应用场景,解决缓存穿透
目录 一、redis 二、布隆过滤器 三、缓存穿透问题 四、布隆过滤器解决缓存穿透 一、redis Redis(Remote Dictionary Server)是一种开源的内存数据存储系统,也是一个使用键值对(Key-Value)方式的高性能数据库。Red…...
数据结构中的英文缩写和易忘的专有名词
树与二叉树 满二叉树:每层的节点数都是该层能取到的最大值完全二叉树:在满二叉树的基础上,去掉最下层右面的一些连续叶子节点所形成的二叉树AVL:平衡二叉树。树中任意节点的左子树和右子树高度之差的绝对值不超过1的二叉排序树称…...
Unity C# 之 Http 获取网页的 html 数据,并去掉 html 格式等相关信息
Unity C# 之 Http 获取网页的 html 数据,并去掉 html 格式等相关信息 目录 Unity C# 之 Http 获取网页的 html 数据,并去掉 html 格式等相关信息 一、简单介绍 二、实现原理 三、注意事项 四、效果预览 五、关键代码 一、简单介绍 Unity中的一些知…...
MODBUS TCP转CCLINK IE协议网关cclink通讯异常的处理方法
你是否曾经遇到过需要将不同的设备连接到一个统一的网络中?或者你是否曾经遇到过设备之间的通讯协议不兼容的问题?捷米的JM-CCLKIE-TCP通讯网关就是为解决这些问题而设计的。 JM-CCLKIE-TCP通讯网关是一款自主研发的CCLINK IE FIELD BASIC从站功能的通讯…...
linux中的ifconfig和ip addr
在linux操作系统中ifconfig和ip addr都是显示网卡配置信息的命令,好多人有疑惑它们有什么区别呢 区别1:对于linux发行的版本不一样 ip addr是对新发行版本的linux使用会比较多;而ifconfig是老版本遇到使用的会比较多。 区别2:显…...
图像多目标跟踪
目标跟踪(Object Tracking)是自动驾驶中常见的任务,根据跟踪目标数量的不同,目标跟踪可分为: 单目标跟踪(Single Object Tracking,SOT)多目标跟踪(Multi-Objects Tracki…...
42 | 航空公司客户价值分析
民航的竞争除了三大航空公司之间的竞争之外,还将加入新崛起的各类小型航空公司、民营航空公司,甚至国外航空巨头。航空产品生产过剩,产品同质化特征愈加明显,于是航空公司从价格、服务间的竞争逐渐转向对客户的竞争。 目前航空公司已积累了大量的会员档案信息和其乘坐航班…...
第三章 图论 No.11二分图,匈牙利算法与点覆盖
文章目录 二分染色:257. 关押罪犯增广路径372. 棋盘覆盖 最小点覆盖376. 机器任务 最大独立集378. 骑士放置 最小路径点覆盖 二分染色:257. 关押罪犯 257. 关押罪犯 - AcWing题库 最大最小问题,一眼二分 答案的范围在 [ 1 , 1 e 9 ] [1, 1…...
Die2Die(D2D)和chip2chip(C2C)之间的高速互联接口
随着chiplet的兴起,Die2Die的高速互联越来越重要,相比于传统的C2C(chip2chip)的互联,D2D的片间距离很近(10mm量级),且这些小的chip(裸片)最终形成一个封装【多芯片模块(MCM)】。所以D2D的互联信道短&#x…...
JAVA设计模式汇总
文章目录 一、设计模式分为三大类二、设计模式的六大原则三、汇总 一、设计模式分为三大类 创建型模式共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。 结构型模式共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式…...
《Qt C++ 与 OpenCV:解锁视频播放程序设计的奥秘》
引言:探索视频播放程序设计之旅 在当今数字化时代,多媒体应用已渗透到我们生活的方方面面,从日常的视频娱乐到专业的视频监控、视频会议系统,视频播放程序作为多媒体应用的核心组成部分,扮演着至关重要的角色。无论是在个人电脑、移动设备还是智能电视等平台上,用户都期望…...
什么是EULA和DPA
文章目录 EULA(End User License Agreement)DPA(Data Protection Agreement)一、定义与背景二、核心内容三、法律效力与责任四、实际应用与意义 EULA(End User License Agreement) 定义: EULA即…...
CMake控制VS2022项目文件分组
我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...
DingDing机器人群消息推送
文章目录 1 新建机器人2 API文档说明3 代码编写 1 新建机器人 点击群设置 下滑到群管理的机器人,点击进入 添加机器人 选择自定义Webhook服务 点击添加 设置安全设置,详见说明文档 成功后,记录Webhook 2 API文档说明 点击设置说明 查看自…...
如何更改默认 Crontab 编辑器 ?
在 Linux 领域中,crontab 是您可能经常遇到的一个术语。这个实用程序在类 unix 操作系统上可用,用于调度在预定义时间和间隔自动执行的任务。这对管理员和高级用户非常有益,允许他们自动执行各种系统任务。 编辑 Crontab 文件通常使用文本编…...
Canal环境搭建并实现和ES数据同步
作者:田超凡 日期:2025年6月7日 Canal安装,启动端口11111、8082: 安装canal-deployer服务端: https://github.com/alibaba/canal/releases/1.1.7/canal.deployer-1.1.7.tar.gz cd /opt/homebrew/etc mkdir canal…...
学习 Hooks【Plan - June - Week 2】
一、React API React 提供了丰富的核心 API,用于创建组件、管理状态、处理副作用、优化性能等。本文档总结 React 常用的 API 方法和组件。 1. React 核心 API React.createElement(type, props, …children) 用于创建 React 元素,JSX 会被编译成该函数…...
LSTM-XGBoost多变量时序预测(Matlab完整源码和数据)
LSTM-XGBoost多变量时序预测(Matlab完整源码和数据) 目录 LSTM-XGBoost多变量时序预测(Matlab完整源码和数据)效果一览基本介绍程序设计参考资料 效果一览 基本介绍 普通的多变量时序已经用腻了,审稿人也看烦了&#…...
【立体匹配】:双目立体匹配SGBM:(1)运行
注:这是一个专题,我会一步步介绍SGBM的实现,按照我的使用和优化过程逐步改善算法,附带实现方法 系列文章【立体匹配】:双目立体匹配SGBM:(1)运行 【立体匹配】:双目立体匹…...
SQL 注入开放与修复
开发: SQL 注入是一种数据库攻击手段。攻击者通过向应用程序提交恶意代码来改变原 SQL 语句的含义, 进而执行任意 SQL 命令,达到入侵数据库乃至操作系统的目的。 例如:下面代码片段中,动态构造并执行了一个 SQ…...
