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

继承

  • 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.mfbz.cn/a/761955.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

网络爬虫(一)

1. 深度优先爬虫:深度优先爬虫是一种以深度为优先的爬虫算法。它从一个起始点开始,先访问一个链接,然后再访问该链接下的链接,一直深入地访问直到无法再继续深入为止。然后回溯到上一个链接,再继续深入访问下一个未被访…

2024年数据和AI趋势报告深度解析:洞悉未来,引领变革

在数字化浪潮的推动下,人工智能(AI)和大数据技术正以前所未有的速度重塑着我们的工作和生活方式。Google Cloud发布的《2024年数据和AI趋势报告》为我们提供了一个窗口,让我们得以窥见未来几年内这些技术可能带来的变革。本文将深…

Dev++软件连接Sqlite

Dev中的C语言使用连接sqlite数据库 1.下载sqlite3.dll和sqlite3.h sqlite3.dll类似于.c文件,封装了函数的原型。 sqlite3.h库文件声明函数。 官网地址下载:sqlite sqlite-amalgamation-3460000.zipsqlite-dll-win-x64-3460000.zip 2.新建c项目 1. …

【python】最新版抖音s逆向拿到数据,非常详细教程(附完整代码)

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全…

服务器数据恢复—EVA存储RAID管理信息丢失的数据恢复案例

意外断电导致raid硬件损坏或者riad管理信息丢失等raid模块损坏而导致数据丢失的情况非常普遍。正常情况下,磁盘阵列一旦创建完成就不会再对管理模块中的信息进行更改,但是raid管理模块中的信息属于可修改信息,一次或多次的意外断电可能会导致…

互联网场景下人脸服务解决方案优化设计

1.简介 1.1目的 在过去的一段时间里,因为听见科技业务对人脸服务的需求,所有针对互联网视频中关键人物定位的检索任务,进行了基于互联网场景的人脸基线服务的构建。本文档是针对当前基线解决方案进行优化的方案设计文档。 1.2范围 本文档描述…

2024 全球软件研发技术大会来了!NineData创始人CEO叶正盛将分享《云原生实时数据复制技术原理与实践》主题演讲

2024年7月4-5日,由 CSDN 和 Boolan 联合主办的「2024 全球软件研发技术大会(SDCon)」将在北京威斯汀酒店举行,将成为引领行业迈向 AI 2.0 时代的重要桥梁。NineData 创始人&CEO叶正盛受邀参会,并将带来《云原生实时…

怎么采集天猫的商品或店铺数据

怎么使用简数采集器批量采集天猫的商品或店铺相关信息呢? 简数采集器暂时不支持采集天猫的商品或店铺相关数据,只能采集页面公开显示的信息,谢谢。 简数采集器抓取网页数据特别简单,不需要懂技术写代码,只需填写网址…

ROS2用c++开发参数节点通信

1.创建节点 cd chapt4/chapt4_ws/ ros2 pkg create example_parameters_rclcpp --build-type ament_cmake --dependencies rclcpp --destination-directory src --node-name parameters_basic --maintainer-name "joe" --maintainer-email "1027038527qq.com&…

大数据开发助手:Coze平台上一款致力于高效解决大数据开发问题的智能Bot!

大数据开发助手:Coze平台上一款致力于高效解决大数据开发问题的智能Bot 核心技术揭秘1. **自然语言处理(NLP)**2. **知识图谱构建**3. **个性化推荐算法** 功能特色概览1. **即时问题解答**2. **最佳实践分享**3. **个性化学习路径**4. **社区…

在 CentOS 上安装 Docker Engine

前言 Docker 是啥之类的就不必多说了,直接上安装步骤。 官网安装教程地址:https://docs.docker.com/engine/install/centos/ 1.Uninstall old versions (卸载旧版本) Older versions of Docker went by docker or docker-engin…

error LNK2019: 无法解析的外部符号 _SDL_main,该符号在函数 _main_getcmdline 中被引用

VC MFC情况下出现此问题, 网上搜索了很多文章无法解决。 error LNK2019: 无法解析的外部符号 _SDL_main,该符号在函数 _main_utf8 中被引用_sdl2main.lib出现无法解析的外部符号-CSDN博客 字符集必须设置为:

【Android面试八股文】性能优化相关面试题: 什么是内存抖动?什么是内存泄漏?

文章目录 一、什么是内存抖动?内存抖动的问题卡顿OOM(Out Of Memory)二、什么是内存泄漏(Memory Leak)?引用计数法可达性分析法一、什么是内存抖动? 在Java中,每创建一个对象,就会申请一块内存,存储对象信息; 每分配一块内存,程序的可用内存也就少一块; 当程序…

SwiftUI八与UIKIT交互

代码下载 SwiftUI可以在苹果全平台上无缝兼容现有的UI框架。例如,可以在SwiftUI视图中嵌入UIKit视图或UIKit视图控制器,反过来在UIKit视图或UIKit视图控制器中也可以嵌入SwiftUI视图。 本文展示如何把landmark应用的主页混合使用UIPageViewController和…

VaRest插件常用节点以及Http请求数据

1.解析json (1)Construct Json Object:构建json对象 (2)Decode Json:解析json 将string转换为json (3)Encode json:将json转换为string (4)Get S…

非标设备行业的数智化项目管理

近年来,中国制造快速发展,企业迫切需要加快转型升级。与传统制造业相比,高端制造业具有明显的优势:高技术、高附加值、低污染、低排放、竞争优势强。一方面,企业对于生产效率和自动化水平的要求不断提高,期…

[vue2/vue3] 详细剖析watch、computed、watchEffect的区别,原理解读

前言:哈喽,大家好,我是前端菜鸟的自我修养!今天给大家分享【深入剖析watch、computed、watchEffect的区别】,并提供具体代码帮助大家深入理解,彻底掌握!原创不易,如果能帮助到带大家…

安装docker compose与elasticsearch,kibana

1.docker compose安装 1.1是否已安装docker docker -v 1.2安装docker compose curl -SL https://github.com/docker/compose/releases/download/v2.18.0/docker-compose-linux-x86_64 -o /usr/local/bin/docker-composeps:如果网络太慢可直接在博客中下载附属文件 下载后修…

缺失d3dx9_43.dll是怎么回事?教你几种靠谱的解决方法

在日常生活和工作中,电脑已经成为我们不可或缺的工具。然而,在使用电脑的过程中,我们常常会遇到一些问题,其中之一就是软件运行时提示d3dx9_43.dll丢失。这个问题会导致软件游戏无法启动运行,但只要我们了解其原因和解…

光扩散微球市场增长空间大 我国已实现其产业化

光扩散微球市场增长空间大 我国已实现其产业化 光扩散微球是一种高性能微球材料,具有优异的光学和力学性能,且不含杂质,将其涂抹在光扩散膜(板)上,可以将点光源变成面光源,使显示面板的布光更加…