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

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 子类 : 继承方式 基类
{};

image-20230813211527815

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

image-20230813212440542

继承方式public继承protected继承private继承
父类public成员子类的public成员子类的protected成员子类的private成员
父类的protected成员子类的protected成员子类的protected成员子类的private成员
父类的private成员子类不可见子类不可见子类不可见

这里其实很好分辨,我们只需要取权限小的即可:public>protected>private

对于public成员,我们可以直接在类的外面访问调用,而对于protected成员,可在类里面通过this指针访问,而private成员,虽然继承到了派生类对象中,但无法访问到,也可以理解为将父类的成员设为private就是不想让其他类继承

image-20230813220139015

但是在实际应用过程中,一般都是采用的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. 派生类和基类的赋值问题

派生类和基类之间的赋值操作涉及到对象切片的问题。派生类的对象可以赋值给基类对象/基类指针/基类引用 ,但反过来(将基类对象赋值给派生类对象)是不合法的,因为这可能导致对象切片,即派生类对象的额外成员信息丢失

image-20230813222919821

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

image-20230813223945086

🦩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的这些成员呢?

image-20230813225150530

通过监视窗口发现,这里A是被B继承了,但是由于成员名相同,A被B给隐藏了,这也叫重定义

如果要访问基类的成员,可使用基类:基类成员显示访问,这也可理解问他们都有着独立的作用域

image-20230813225536058

🐓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
{};

多继承会引发一个很麻烦的问题——菱形继承

image-20230814002934232

我们先来上代码

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是属于继承的哪个类,从而产生二义性的问题。

image-20230814003431003

当然,前面也提到过,可以通过指定类域,来明确告诉编译器,这属于哪个类

D d;
d.B::_a = 1;
d.C::_a = 2;
d._b = 3;
d._c = 4;
d._d = 5;

这样虽然解决了二义性的问题,但是这样看的数据十分冗余,很容易分不清哪个是哪个

image-20230814004447944

为了填补这个坑,推出了一种名为虚拟继承的继承方式(仅限菱形继承使用,其他地方不要使用)

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,只有一份了,而且我们查看内存发现,数据并不是连在一起,多了一些地址

image-20230814011531088

这叫做虚基表,用来寻找基类偏移量的表,虚拟继承的派生类里面就包含了这个虚表,这个虚表记录着距离基类的偏移量,如果要用到基类的数据,加上这个距离就能找到,这样就解决了数据的二义性和数据冗余的问题。

但是在实际过程中,这个模型十分鸡肋且复杂,所以一般都不会采用这种继承方式。


多继承就属于C++语法复杂的一个体现,而继承虽然可以复用,但是继承的耦合度十分高,代码直接的依赖关系很强,这样就造成了代码的不便于维护。但又涉及到多态必须使用继承,所以在实际之中,代码要复用的话,我们得分场景。
那本期的方向就到这咯,我们下期再见,如果有下期的话。

相关文章:

C++——继承

文章目录 &#x1f99c;1. 什么是继承&#x1f40a;1.1 概念&#x1f40a;1.2 格式&#x1f40a;1.3 继承方式 & 访问限定符 &#x1f426;2. 派生类和基类的赋值问题&#x1f9a9;3. 派生类和基类同名成员问题&#x1f413;4.派生类默认成员函数&#x1f409;4.1 构造函数…...

openGauss学习笔记-38 openGauss 高级数据管理-游标

文章目录 openGauss学习笔记-38 openGauss 高级数据管理-游标38.1 语法格式38.2 参数说明38.3 示例 openGauss学习笔记-38 openGauss 高级数据管理-游标 为了处理SQL语句&#xff0c;存储过程进程分配一段内存区域来保存上下文联系。游标是指向上下文区域的句柄或指针。借助游…...

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. 合并两个排序的链表】

题目 输入两个递增排序的链表&#xff0c;合并这两个链表并使新链表中的节点仍然是递增排序的。 示例1&#xff1a; 输入&#xff1a;1->2->4, 1->3->4输出&#xff1a;1->1->2->3->4->4 限制&#xff1a; 0 < 链表长度 < 1000 解题思路 1…...

前端盒子模型

day05-盒子模型 目标&#xff1a;掌握盒子模型组成部分&#xff0c;使用盒子模型布局网页区域 01-选择器 结构伪类选择器 基本使用 作用&#xff1a;根据元素的结构关系查找元素。 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(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的优势 转自&#xff1a;https://zhuanlan.zhihu.com/p/630981648 如有侵权&#xff0c;请联系删除 big.L…...

【BASH】回顾与知识点梳理(十四)

【BASH】回顾与知识点梳理 十四 十四. 文件与目录的默认权限与隐藏权限14.1 文件预设权限&#xff1a;umaskumask 的利用与重要性&#xff1a;专题制作 14.2 文件隐藏属性chattr (配置文件案隐藏属性)lsattr (显示文件隐藏属性) 14.3 文件特殊权限&#xff1a; SUID, SGID, SBI…...

乡村振兴指数与其30余个原始变量数据(2000-2022年)

乡村振兴是当下经济学研究的热点之一&#xff0c;对乡村振兴进行测度&#xff0c;是研究基础。测度乡村振兴水平的学术论文广泛发表在《数量经济技术经济研究》等顶刊上。整理了2000-2022年城市层面的乡村振兴指数与其30余个原始变量数据&#xff0c;供大家使用。 数据来源&…...

深入理解MySQL表的操作和管理

MySQL是一种广泛使用的关系型数据库管理系统&#xff0c;用于存储和管理大量结构化数据。在MySQL中&#xff0c;表是数据的基本组织单位&#xff0c;对表的操作和管理能力对于数据库的性能和数据完整性至关重要。本文将深入讨论MySQL表的操作和管理&#xff0c;包括创建表、修改…...

MATLAB图论合集(一)基本操作基础

本帖总结一些经典的图论问题&#xff0c;通过MATLAB如何计算答案。近期在复习考研&#xff0c;以此来巩固一下相关知识——虽然考研肯定不能用MATLAB代码哈哈&#xff0c;不过在实际应用中解决问题还是很不错的&#xff0c;比C易上手得多~ 图论中的图&#xff08;Graph&#xf…...

Redis布隆过滤器的原理和应用场景,解决缓存穿透

目录 一、redis 二、布隆过滤器 三、缓存穿透问题 四、布隆过滤器解决缓存穿透 一、redis Redis&#xff08;Remote Dictionary Server&#xff09;是一种开源的内存数据存储系统&#xff0c;也是一个使用键值对&#xff08;Key-Value&#xff09;方式的高性能数据库。Red…...

数据结构中的英文缩写和易忘的专有名词

树与二叉树 满二叉树&#xff1a;每层的节点数都是该层能取到的最大值完全二叉树&#xff1a;在满二叉树的基础上&#xff0c;去掉最下层右面的一些连续叶子节点所形成的二叉树AVL&#xff1a;平衡二叉树。树中任意节点的左子树和右子树高度之差的绝对值不超过1的二叉排序树称…...

Unity C# 之 Http 获取网页的 html 数据,并去掉 html 格式等相关信息

Unity C# 之 Http 获取网页的 html 数据&#xff0c;并去掉 html 格式等相关信息 目录 Unity C# 之 Http 获取网页的 html 数据&#xff0c;并去掉 html 格式等相关信息 一、简单介绍 二、实现原理 三、注意事项 四、效果预览 五、关键代码 一、简单介绍 Unity中的一些知…...

MODBUS TCP转CCLINK IE协议网关cclink通讯异常的处理方法

你是否曾经遇到过需要将不同的设备连接到一个统一的网络中&#xff1f;或者你是否曾经遇到过设备之间的通讯协议不兼容的问题&#xff1f;捷米的JM-CCLKIE-TCP通讯网关就是为解决这些问题而设计的。 JM-CCLKIE-TCP通讯网关是一款自主研发的CCLINK IE FIELD BASIC从站功能的通讯…...

linux中的ifconfig和ip addr

在linux操作系统中ifconfig和ip addr都是显示网卡配置信息的命令&#xff0c;好多人有疑惑它们有什么区别呢 区别1&#xff1a;对于linux发行的版本不一样 ip addr是对新发行版本的linux使用会比较多&#xff1b;而ifconfig是老版本遇到使用的会比较多。 区别2&#xff1a;显…...

图像多目标跟踪

目标跟踪&#xff08;Object Tracking&#xff09;是自动驾驶中常见的任务&#xff0c;根据跟踪目标数量的不同&#xff0c;目标跟踪可分为&#xff1a; 单目标跟踪&#xff08;Single Object Tracking&#xff0c;SOT&#xff09;多目标跟踪&#xff08;Multi-Objects Tracki…...

42 | 航空公司客户价值分析

民航的竞争除了三大航空公司之间的竞争之外,还将加入新崛起的各类小型航空公司、民营航空公司,甚至国外航空巨头。航空产品生产过剩,产品同质化特征愈加明显,于是航空公司从价格、服务间的竞争逐渐转向对客户的竞争。 目前航空公司已积累了大量的会员档案信息和其乘坐航班…...

第三章 图论 No.11二分图,匈牙利算法与点覆盖

文章目录 二分染色&#xff1a;257. 关押罪犯增广路径372. 棋盘覆盖 最小点覆盖376. 机器任务 最大独立集378. 骑士放置 最小路径点覆盖 二分染色&#xff1a;257. 关押罪犯 257. 关押罪犯 - AcWing题库 最大最小问题&#xff0c;一眼二分 答案的范围在 [ 1 , 1 e 9 ] [1, 1…...

Die2Die(D2D)和chip2chip(C2C)之间的高速互联接口

随着chiplet的兴起&#xff0c;Die2Die的高速互联越来越重要&#xff0c;相比于传统的C2C(chip2chip)的互联&#xff0c;D2D的片间距离很近(10mm量级)&#xff0c;且这些小的chip(裸片)最终形成一个封装【多芯片模块&#xff08;MCM&#xff09;】。所以D2D的互联信道短&#x…...

JAVA设计模式汇总

文章目录 一、设计模式分为三大类二、设计模式的六大原则三、汇总 一、设计模式分为三大类 创建型模式共五种&#xff1a;工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。 结构型模式共七种&#xff1a;适配器模式、装饰器模式、代理模式、外观模式、桥接模式…...

树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法

树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源&#xff1a; http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作&#xff0c;无需更改相机配置。但是&#xff0c;一…...

day52 ResNet18 CBAM

在深度学习的旅程中&#xff0c;我们不断探索如何提升模型的性能。今天&#xff0c;我将分享我在 ResNet18 模型中插入 CBAM&#xff08;Convolutional Block Attention Module&#xff09;模块&#xff0c;并采用分阶段微调策略的实践过程。通过这个过程&#xff0c;我不仅提升…...

Golang dig框架与GraphQL的完美结合

将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用&#xff0c;可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器&#xff0c;能够帮助开发者更好地管理复杂的依赖关系&#xff0c;而 GraphQL 则是一种用于 API 的查询语言&#xff0c;能够提…...

cf2117E

原题链接&#xff1a;https://codeforces.com/contest/2117/problem/E 题目背景&#xff1a; 给定两个数组a,b&#xff0c;可以执行多次以下操作&#xff1a;选择 i (1 < i < n - 1)&#xff0c;并设置 或&#xff0c;也可以在执行上述操作前执行一次删除任意 和 。求…...

【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验

系列回顾&#xff1a; 在上一篇中&#xff0c;我们成功地为应用集成了数据库&#xff0c;并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了&#xff01;但是&#xff0c;如果你仔细审视那些 API&#xff0c;会发现它们还很“粗糙”&#xff1a;有…...

爬虫基础学习day2

# 爬虫设计领域 工商&#xff1a;企查查、天眼查短视频&#xff1a;抖音、快手、西瓜 ---> 飞瓜电商&#xff1a;京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空&#xff1a;抓取所有航空公司价格 ---> 去哪儿自媒体&#xff1a;采集自媒体数据进…...

vue3+vite项目中使用.env文件环境变量方法

vue3vite项目中使用.env文件环境变量方法 .env文件作用命名规则常用的配置项示例使用方法注意事项在vite.config.js文件中读取环境变量方法 .env文件作用 .env 文件用于定义环境变量&#xff0c;这些变量可以在项目中通过 import.meta.env 进行访问。Vite 会自动加载这些环境变…...

C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。

1.先用Visual Studio 2017打开Yichip YC31xx loader.vcxproj&#xff0c;再用Visual Studio 2022打开。再保侟就有.sln文件了。 易兆微芯片下载工具加开机动画下载 ExtraDownloadFile1Info.\logo.bin|0|0|10D2000|0 MFC应用兼容CMD 在BOOL CYichipYC31xxloaderDlg::OnIni…...

七、数据库的完整性

七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...

在 Spring Boot 中使用 JSP

jsp&#xff1f; 好多年没用了。重新整一下 还费了点时间&#xff0c;记录一下。 项目结构&#xff1a; pom: <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://ww…...