【C++ | 继承】|概念、方式、特性、作用域、6类默认函数

news2024/7/8 2:03:22

继承

  • 1.继承的概念与定义
  • 2.继承的方式
      • 2.1继承基本特性
      • 2.2继承的作用域
        • 2.2.1隐藏
        • 赋值兼容
      • 派生类的创建和销毁
        • 构造函数
        • 拷贝构造
        • 赋值重载

1.继承的概念与定义

继承是面向对象编程中的一个重要概念。它的由来可以追溯到软件开发中的模块化设计代码复用的需求。

在软件开发过程中,我们经常会遇到需要为多个类添加相同的行为或属性的场景,这样就产生了代码重复的问题。为了解决这个问题,工程师们开始寻找一种方法来实现代码的复用。

继承就是一种解决代码复用问题的方式。它允许我们创建一个新的类,继承自一个已经存在的类,从而继承和复用父类的属性和方法。通过继承,我们可以在不改变父类的前提下,为子类添加额外的属性和方法,实现功能的扩展。

继承方式的由来可以追溯到早期的面向对象编程语言。早期的面向对象编程语言如Smalltalk、Simula等提供了基于类的继承机制。后来的编程语言如Java、C++等也引入了类似的继承机制。继承方式的由来和发展是为了提高软件开发的效率和可维护性,同时也体现了面向对象编程的思想和原则。

总而言之,在C++中,继承是代码复用的最重要手段。

2.继承的方式

那么我们要如何实现继承呢?
先看个样例,再看语法规则:

class parent
{
public:
	int _age;
};

class child : public parent
{
public:
	int _id;
};
  • 以上就是一个简单的继承结构,child继承了parent。

  • 其中parent这种被别人继承的类叫做:基类 / 父类

  • child这种继承别人的类叫做:派生类 / 子类

  • public parent这条语句,紧跟在child的类名后面,说明child继承了parent。而public是继承方式

这个继承方式有什么作用呢?

继承方式与基类的成员访问限定符共同决定了派生类对基类成员的访问权限

基类成员 \ 继承方式public继承protect继承private继承
public成员派生类的public成员派生类的protect成员派生类的private成员
protect成员派生类的protect成员派生类的protect成员派生类的private成员
private成员不可见不可见不可见
  • 以上表格展示了所有情况下的继承,基类的成员会根据自身的访问属性以及继承方式,共同决定最终继承到派生类的成员是什么属性。

  • 其中,不可见不是指不继承,基类中的private成员继承后在派生类中不可见,就是派生类无法直接访问到这个成员,但是派生类依然是存储着这个成员的。

当然,与访问限定符一样,继承方式也是有默认方式

  • 用class定义的类,默认继承方式是private
  • 用struct定义的类,默认的继承方式是public

  • 多继承:
    一个派生类可以同时继承多个基类:
class parent1
{
public:
	int _age;
};

class child : public parent1, public parent2
{
public:
	int _id;
};

2.1继承基本特性

  • 继承后,派生类有可能只增改了基类的成员函数,而成员变量是一样的,所以基类和派生类的大小可能是一样的
  • 友元关系不能继承,基类的友元不能访问子类的私有和保护成员
  • 对于基类的静态成员,派生类和基类共用,派生类不会额外创建静态成员
  • 如果不希望一个类被继承,可以将这个类的构造函数或者析构函数用private修饰
    继承后,派生类的初始化列表指向顺序为继承顺序

2.2继承的作用域

基类与派生类有两个分别独立的作用域

2.2.1隐藏

当派生类继承了基类的成员后,如果派生类自己创建了与基类同名的成员,那么派生类成员将屏蔽对同名基类成员的直接访问,这种情况叫做隐藏。

class A
{
	void func()
	{}

public:
	int num;
};

class B : public A
{
	void func()
	{}

public:
	int num;
};

在以上继承关系中,B继承了A的num变量func函数,而B类自己还创建了同名的func与num。那么此时在B内部直接访问num与func,就是访问B自己的num。如果想要访问A的成员,需要限定作用域

B b;
b.func();//访问B的func函数
b.A::func();//访问A的func函数
  • 此外,函数重载要求两个函数在同一个作用域,而基类与派生类是两个不同作用域,所以就算参数不同也不能构成重载。所以只要基类与派生类内的函数名相同就构成隐藏,不考虑参数

赋值兼容

赋值兼容是一个基类与派生类之间的转换规则,其可以让派生类转换为父类。

以如下的继承关系做讲解:

class person
{
public:
	string _name;
	string _sex;
	int _age;
};

class student : public person
{
public:
	int _No;
};

规则

派生类的对象可以赋值给基类的对象

student s;
person p = s;

赋值如下图


在这里插入图片描述


我们可以将一个派生类的成员赋值给基类成员,此时会发生一个切片效果,基类只取出派生类中属于基类的部分来构造基类。

派生类的指针可以转换为基类的指针
派生类的引用可以转换为基类的引用

student s;
person* pp = &s;
person& rp = s;

在这里插入图片描述


基类是被包含在派生类中的,所以我们用基类的指针去访问派生类,相当于只访问了基类的部分。上图中就是只访问了红色的部分。


派生类的创建和销毁

派生类是如何创建销毁的?因为派生类内部还包含了一个基类,那么基类这一部分要如何处理?
其实想要理解这一部分,就记住一句话:派生类的默认成员函数,把基类当作一个类成员变量处理

接下来我为大家讲解构造函数,拷贝构造,赋值重载,析构函数这几个与创建销毁相关的函数,来理解派生类是如何创建销毁的。

构造函数

派生类构造函数将基类当作一个成员变量,不会直接初始化基类的成员,而是通过调用基类的构造函数

在一般的类中,类内部如果有其他类的成员变量,构造函数会在初始化列表调用其构造函数。如果不直接调用,那么会隐式调用其相应的默认构造函数。

class person
{
public:
	string _name;
};

class child : public parent
{
public:
	child(string name, int num)
		:parent(name)
		,_num(num)
	{}
private:
	int _num;
};

:parent(name) 就是在初始化列表显式地调用构造函数。

拷贝构造

派生类拷贝构造将基类当作一个成员变量,不会直接拷贝基类的成员,而是通过调用基类的拷贝构造。

在一般的类中,类内部如果有其他类的成员变量,拷贝构造会在初始化列表调用其拷贝构造。如果不直接调用,那么会隐式调用其相应的默认构造函数。

class person
{
public:
	string _name;
};

class child : public parent
{
public:
	child(const child& c)
		:parent(c)
		,_num(c.num)
	{}
private:
	int _num;
};
  • parent ( c ) 就是在显式调用基类的拷贝构造,不过我们在调用基类的拷贝构造时,传入的却是派生类的引用。这是为什么?❓❔❓
  • 我们刚在赋值兼容处说过:派生类的引用可以转化为基类的引用
  • 所以此处在传参时会发生一次隐式的切片,基类的拷贝构造只访问派生类的基类部分,来拷贝出一个基类。

要注意:拷贝构造也属于构造函数,所以拷贝构造在初始化列表中如果没有显式调用拷贝构造,就会隐式调用默认构造函数


赋值重载

在派生类拷贝构造中,必须显式调用基类的赋值重载,因为赋值重载也把基类当作一个类成员做处理。赋值重载不会直接调用成员的赋值重载,而是需要我们显式调用。

class person
{
public:
	string _name;
};

class child : public parent
{
public:
	child& operator=(const child& c)
	{
		parent::operator=(c);
		_num= c._num;
	}
private:
	int _num;
};

parent::operator=(c );就是在显式地调用基类的拷贝构造,这里不能直接调用operator=(c );,因为派生类中存在operator=;这个函数,基类的函数被隐藏了,所以我们要指定作用域,来调用基类的赋值重载。

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

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

相关文章

山西车间应用LP-LP-SCADA系统的好处有哪些

关键字:LP-SCADA系统, 传感器可视化, 设备可视化, 独立SPC系统, 智能仪表系统,SPC可视化,独立SPC系统 LP-SCADA(监控控制与数据采集)系统是工业控制系统的一种,主要用于实时监控、控制和管理工业生产过程。 在车间应用LP-SCADA系统&#xf…

【项目日记(四)】搜索引擎-Web模块

❣博主主页: 33的博客❣ ▶️文章专栏分类:项目日记◀️ 🚚我的代码仓库: 33的代码仓库🚚 🫵🫵🫵关注我带你了解更多项目内容 目录 1.前言2.前端模块2.1页面设计2.2后端交互 3.部署到云服务器4.总结 1.前言 在前面的文…

25届最近5年华北电力大学自动化考研院校分析

华北电力大学(北京保定) 目录 一、学校学院专业简介 二、考试科目指定教材 三、近5年考研分数情况 四、近5年招生录取情况 五、最新一年分数段图表 六、初试大纲复试大纲 七、学费&奖学金&就业方向 一、学校学院专业简介 二、考试科目指…

论文导读 | knowledge-based VQA

背景介绍 传统的视觉问答(Visual Question Answering, VQA)基准测试主要集中在简单计数、视觉属性和物体检测等问题上,这些问题不需要超出图像内容的推理或知识。然而,在knowledge-based VQA中,仅靠图像无法回答给定的…

DA-LSTM多输入分类|蜻蜓算法-长短期神经网络|Matlab

目录 一、程序及算法内容介绍: 基本内容: 亮点与优势: 二、实际运行效果: 三、算法介绍: 四、完整程序下载: 一、程序及算法内容介绍: 基本内容: 本代码基于Matlab平台编译&am…

大疆2025校招内推

需要内推码的请留言哦 期待你的加入

哪个麦克风唱歌效果好,哪个麦克风好,无线麦克风十大排名分享

​在数字化时代的背景下,声音的传播与记录变得日益重要。无论是会议室、教室还是户外场所,无线领夹麦克风凭借其便携性和稳定的连接性能,成为人们沟通表达的首选工具。面对众多选择,我为你精选了几款性能卓越且性价比高的无线领夹…

DVWA sql手注学习(巨详细不含sqlmap)

这篇文章主要记录学习sql注入的过程中遇到的问题已经一点学习感悟,过程图片会比较多,比较基础和详细,不存在看不懂哪一步的过程 文章目录 靶场介绍SQL注入 lowSQL注入 MediumSQL注入 HighSQL注入 Impossible 靶场介绍 DVWA(Damn…

巴图自动化Modbus协议转Profinet协议网关模块连智能仪表与PLC通讯

一、现场要求:PLC作为控制器,仪表设备作为执行设备。执行设备可以实时响应PLC传送的指令,并将数据反馈给PLC,从而实现PLC对仪表设备的控制和监控,实现对生产过程的精确控制。 二、解决方案:通过巴图自动化Modbus协议转Profinet协议…

C++ 智能指针内存泄漏问题

shared_ptr相互嵌套导致循环引用 代码示例 #include <iostream> #include <memory> using namespace std;class B;class A { public:std::shared_ptr<B> b_ptr;~A() { std::cout << "A destroyed\n"; } };class B { public:std::shared_pt…

明星代言6个提升企业形象的杀手锏-华媒舍

在当今竞争激烈的商业世界中&#xff0c;企业形象的塑造对于品牌的发展至关重要。而明星代言作为一种常见的营销手段&#xff0c;被广泛使用来提升企业形象和产品销售。本文将介绍明星代言的六个杀手锏&#xff0c;帮助您了解如何通过明星代言来提升企业形象。 1. 拥有广泛的影…

PCB设计时,信号走线要先过ESD/TVS管,这是为什么?

目录 为什么有上面这个问题&#xff1f; 问题的原因——走线电感 走线电感的阻抗 电感的影响 小结 都说接口处的信号要先过ESD/TVS管&#xff0c;然后拉到被保护器件&#xff0c;为什么不这样做效果就不好&#xff1f;那如果受板子实际情况限制&#xff0c;必须这样layout…

专题二:Spring源码编译

目录 下载源码 配置Gradle 配置环境变量 配置setting文件 配置Spring源码 配置文件调整 问题解决 完整配置 gradel.properties build.gradle settiings.gradel 在专题一&#xff1a; Spring生态初探中我们从整体模块对Spring有个整体的印象&#xff0c;现在正式从最…

经典卷积神经网络 LeNet

一、实例图片 #我们传入的是28*28&#xff0c;所以加了padding net nn.Sequential(nn.Conv2d(1, 6, kernel_size5, padding2), nn.Sigmoid(),nn.AvgPool2d(kernel_size2, stride2),nn.Conv2d(6, 16, kernel_size5), nn.Sigmoid(),nn.AvgPool2d(kernel_size2, stride2),nn.Flat…

Android EditText的属性与用法

EditText 是编辑框控件&#xff0c;可以接收用户输入&#xff0c;并在程序中对用户输入进行处理。EditText在App里随处可见&#xff0c;在进行搜索、聊天、拨号等需要输入信息的场合&#xff0c;都可以使用 EditText。 图1 编辑框示意图 EditText 是TextView的子类&#xff0c…

吴恩达深度学习笔记:机器学习策略(2)(ML Strategy (2)) 2.5-2.6

目录 第三门课 结构化机器学习项目&#xff08;Structuring Machine Learning Projects&#xff09;第二周&#xff1a;机器学习策略&#xff08;2&#xff09;(ML Strategy (2))2.5 数据分布不匹配时的偏差与方差的分析&#xff08;Bias and Variance with mismatched data di…

下载安装MySQL

1.软件的下载 打开官网下载mysql-installer-community-8.0.37.0.msi 2.软件的安装 mysql下载完成后&#xff0c;找到下载文件&#xff0c;双击安装 3.配置环境变量 4.自带客户端登录与退出

CSS filter(滤镜)属性,并实现页面置灰效果

目录 一、filter&#xff08;滤镜&#xff09;属性 二、准备工作 三、常用的filter属性值 1、blur(px) 2、brightness(%) 3、contrast(%) 4、grayscale(%) 5、opacity(%) 6、saturate(%) 7、sepia(%) 8、invert(%) 9、hue-rotate(deg) 10、drop-shadow(h-shadow v…

前端JS 插件实现下载【js-tool-big-box,下载大文件(fetch请求 + 下载功能版)

上一节&#xff0c;我们添加了下载大文件的纯功能版&#xff0c;意思就是需要开发者&#xff0c;在自己项目里发送请求&#xff0c;请求成功后&#xff0c;获取文件流的blob数据&#xff0c;然后 js-tool-big-box 帮助下载。 但考虑到&#xff0c;有些项目&#xff0c;可能比较…

装饰模式解析:基本概念和实例教程

目录 装饰模式装饰模式结构装饰模式应用场景装饰模式优缺点练手题目题目描述输入描述输出描述题解 装饰模式 装饰模式&#xff0c;又称装饰者模式、装饰器模式&#xff0c;是一种结构型设计模式&#xff0c;允许你通过将对象放入包含行为的特殊封装对象中来为原对象绑定新的行…