搞清楚[继承],易如反掌
穷不失义,达不离道。——孔丘《论语》
继承
- 1、简单理解
- 2、继承
- 2、1、继承的概念
- 2、2、继承定义
- 2、3、基类和派生类对象赋值转换
- 2、4、继承中的作用域
- 2、5、派生类默认成员函数
- 2、6、继承中的特点
- 2、6、1、友元
- 2、6、2、静态成员
- 2、6、3、菱形继承及菱形虚拟继承
- 3、总结
1、简单理解
封装,继承和多态是C++中不可或缺的组成部分。
封装: 数据和方法放在一起,把想给你访问的定义为公有,不想的定义为私有。就例如:一个类型放到另一个类型里面,通过typedef成员函数调整,封装另一个全新的类型。
继承: 面对对象复用的重要方式->类设计层面上的复用
继承不算是模版,对于模版来说,模版只是一个单纯的一个类,不同的类型,数据类型的不同而已,但是继承不只是类型的区别。
请看一下的图形,第一个表示的是模版的含义,而第二个是继承的含义。
多态: 通俗来说,就是多种形态,具体点就是去完成某个行为,不同对象去完成会产生不同的状态。如果想要更具体的案例,那么现实生活中到处都是,就比如买火车票,不同身份的人买的价格都会不一样,相同的人买几等座价格也是不一样的,这就是一个比较典型的多态案例。
继承和多态更细节的地方会在下面说,这里只是简单的概括一下主体。
2、继承
2、1、继承的概念
继承机制是面向对象程序设计使代码能够复用的重要手段,能够允许程序员在保持原有类的特性的基础之上就行扩展,增加内容和功能,这样产生的类成为派生类。继承展现了面对对象程序设计的层次结构,体现了由简单到复杂的认知过程。
与函数的复用相类似,继承是类设计层次的复用。
class Person
{
public:void Print(){cout << "name:" << _name << endl;cout << "age:" << _age << endl;}
protected:string _name = "peter"; // 姓名int_age=18; //年龄
};
// 继承后父类的Person的成员(成员函数+成员变量)都会变成子类的一部分。这里体现出了 Student和Teacher复用了Person的成员。下面我们使用监视窗口查看Student和Teacher对象,可 以看到变量的复用。调用Print可以看到成员函数的复用。
class Student : public Person
{
protected:int _stuid; // 学号
};class Teacher : public Person
{protected:int _jobid; // 工号
};
int main()
{Student s;Teacher t;s.Print();t.Print();return 0;
}
2、2、继承定义
派生类和基类的名字是根据程序员自行定义的,无所谓叫什么。
其中继承方式有三种,分别是private,protect和public。
当然继承方式和访问限定符的共同作用下才能知道成员变量或者是成员函数到底有了怎么样子的改变。
总结:
- 基类private成员在派生类中无论以什么方式继承都是不可见的。这里的不可见是指基类的私有成员还是被继承到了派生类对象中,但是语法上限制派生类对象不管在类里面还是类外面 都不能去访问它。
- 基类private成员在派生类中是不能被访问,如果基类成员不想在类外直接被访问,但需要在派生类中能访问,就定义为protected。 可以看出保护成员限定符是因继承才出现的。
- 实际上面的表格我们进行一下总结会发现,基类的私有成员在子类都是不可见。基类的其他 成员在子类的访问方式 == Min(成员在基类的访问限定符,继承方式),public > protected > private。
- 使用关键字class时默认的继承方式是private,使用struct时默认的继承方式是public,不过最好显示的写出继承方式。
- 在实际运用中一般使用都是public继承,几乎很少使用protetced/private继承,也不提倡 使用protetced/private继承,因为protetced/private继承下来的成员都只能在派生类的类里 面使用,实际中扩展维护性不强。
2、3、基类和派生类对象赋值转换
派生类对象 能够直接赋值给基类的对象/基类的指针/基类的引用。也能够俗称是切片或者是切割。形象的说明,在赋值的时候是派生类是将整个对象就行部分切割之后再赋值给基类,保证基类的正确性,没有多余的部分。
==基类对象不能赋值给派生类。==很显而易见的是基类的成员并没有多余派生类,如果赋值给派生类,一些部分显而易见的会产生问题,包括但不限于随机赋值,也指针的出现。
2、4、继承中的作用域
每一个成员都有自己的作用域,函数有函数的作用域,变量有变量的作用域,乃至main函数也有自己的作用域,所以继承中的作用域也很重要。
1、继承中的基类和派生类都有独立的作用域。
2、当子类和父类中存在同名函数时,子类成员将会屏蔽父类对同名函数的直接访问,这种情况也叫做隐蔽,也叫重定义
3、成员名相同,就构成隐蔽
4、在设计过程中继承体系最好不要定义同名的成员
这段代码中包含了函数名相同时,出现的隐蔽现象,同时也说明了如果隐蔽了该如何调用基类中的成员函数。
#include<iostream>
#include<string>
using namespace std;
class Person
{
protected:string _name = "小李子"; // 姓名int _num = 111;// 身份证号
};
class Student : public Person
{
public:void Print(){cout << " 姓名:" << _name << endl;cout << " 身份证号:" << Person::_num << endl;cout << " 学号:" << _num << endl;}
protected:int _num = 999; // 学号
};
void Test()
{Student s1;s1.Print();
};
int main()
{Test();return 0;
}
这样的结果也能够说明,隐蔽的效果和消除隐蔽的方法。
需要注意的是!这里是隐蔽而不是函数重载,重载和隐蔽是两码事!
2、5、派生类默认成员函数
- 派生类的构造函数必须调用基类的构造函数初始化基类的那一部分成员。如果基类没有默认 的构造函数,则必须在派生类构造函数的初始化列表阶段显示调用。
- 派生类的拷贝构造函数必须调用基类的拷贝构造完成基类的拷贝初始化。
- 派生类的operator=必须要调用基类的operator=完成基类的复制。
- 派生类的析构函数会在被调用完成后自动调用基类的析构函数清理基类成员。因为这样才能保证派生类对象先清理派生类成员再清理基类成员的顺序。
- 派生类对象初始化先调用基类构造再调派生类构造。
- 派生类对象析构清理先调用派生类析构再调基类的析构。
- 因为后续一些场景析构函数需要构成重写,重写的条件之一是函数名相同(这个我们后面会讲解)。那么编译器会对析构函数名进行特殊处理,处理成destrutor(),所以父类析构函数不加 virtual的情况下,子类析构函数和父类析构函数构成隐藏关系。
构造时,基类构造再到派生类。析构时显示派生类析构然后再是基类。
2、6、继承中的特点
2、6、1、友元
在基类的定义中可能存在友元,友元的存在在继承中又有什么样的特性呢?
首先,友元是不能够继承的 简单点意思就是你爸爸的朋友不是你的朋友。基类的友元不能够访问子类的私有和保护成员。
2、6、2、静态成员
如果在基类中定义了一个static静态成员,那么整个继承体系中只会有一个这样的成员,无论多少个子类,访问的都是同一个static成员。
2、6、3、菱形继承及菱形虚拟继承
在刚刚讲过的所有的案例中,我们的继承都是按照类似线性的关系来进行继承,但是难免在现实中存在多继承的情况出现。所以一个典型的菱形继承就值得我们来了解并且来分析其中可能存在的问题。
这样子的菱形继承就会存在问题,导致一个数据到最后一个类的时候可能会有两个不同的值,不知道该怎么继承,所以菱形继承的问题就是在
1)数据冗余 2)二异性
虽然解决二异性的问题能够在数据前加上限定符来特指某个类中的数据,但是对于数据冗余的问题还是没有解决。
所以这个时候,就需要通过virtual,虚继承的方式来解决问题。
virtual在继承过程中就需要加上,如不是最后的时候才加上。
从内存中能够观察到D对象内部,A,B与C到底怎么储存的,能够类似于类中的函数一样,将A中的a放在最后一个类似于公共的区域,让a只存在一个,改变修改相同的一个a。
那么其中B与C第一行中的那串地址又能代表什么呢,为什么每个的第一行都是一串奇奇怪怪的地址,这究竟是怎么做到能够找到a的地址的呢? 其实就是因为这第一行的地址,才能够让我们找到具体的位置在哪,结下来我们将这串地址放在内存中寻找一下,看看是什么。
也就是这个样子,找到的位置存放的位置之后可以看到存放的第二个地址的地方的数就是按照从当前位置找到公共位置的地址的距离。这样也就说得通两个地址找到A的位置并且能够得到a的值。
用专业的话来说也就是,通过B,C两个指针指向一张表,这两个表就叫虚基表,两个指针就叫虚基表指针。虚基表中存的偏移量可以找到A。
3、总结
其实继承中复杂的大多是是多继承,多继承中又存在菱形继承,有了菱形继承就又会有菱形虚拟继承,有了菱形虚拟继承底层就会变的复杂。所以一般来说都是不设计多继承,即使有着多继承,也尽量不设计菱形继承,否则在复杂度以及性能上都会存在问题。
并且大多数情况之下,继承也可以换成组合的方式来实现。
都能用选组合,其他情况适合什么用什么。
继承的缺点还存在着高耦合的问题。当继承中改变了就会改变后续继承的偶有元素,这样也会造成不少的麻烦,会对后期的修改有较大部分的影响,导致牵一发而动全身的后果。
相关文章:

搞清楚[继承],易如反掌
穷不失义,达不离道。——孔丘《论语》 继承 1、简单理解2、继承2、1、继承的概念2、2、继承定义2、3、基类和派生类对象赋值转换2、4、继承中的作用域2、5、派生类默认成员函数2、6、继承中的特点2、6、1、友元2、6、2、静态成员2、6、3、菱形继承及菱形虚拟继承 3、…...
Perl 语言入门学习指南:探索高效脚本编程的奥秘
引言 Perl,全称Practical Extraction and Report Language,是一种功能强大的编程语言,特别擅长于文本处理、报告生成以及系统自动化管理任务。自1987年诞生以来,Perl凭借其灵活性、强大的内置功能库和广泛的社区支持,…...

【HTML】-解决页面内容无法选择、复制问题
目录 1、网页内容无法选中 1.1、问题原因 1.2、解决脚本 1.2.1、开启控制台窗口 1.2.2、执行脚本命令 2、内容复制弹出阻止框 2.2、解决脚本 1、网页内容无法选中 1.1、问题原因 今天在访问某一网站平台,需要将内容进行选择、复制时发现不可使用。 在使用…...

C#中委托与事件
一、委托 在面向对象中,我们可以将任何数据类型作为参数传递给方法,能否将一个方法作为参数传递给另一个方法?C#中通过委托可以实现将方法作为参数进行传递。 1.1概念 委托是一种引用类型,它可以用于封装并传递方法作为参数。委…...

通用后台管理(二)——项目搭建
目录 前言 一、安装vue-cli依赖 1、使用yarn下载vue-cli 2、使用npm下载 3、检查一下是否下载成功 二、创建项目 1、创建项目,my-app是项目名称 2、 这里选择vue 2,蓝色表示选中的。 3、启动项目 三、下载项目依赖 四、配置项目 1、修改esli…...

多模态大模型之达摩院通义MPLUG
引言 随着人工智能技术的飞速发展,多模态技术逐渐成为研究的热点。它结合了文本、图像、声音等多种数据类型,为机器理解世界提供了更丰富的视角。本文根据严明老师的达摩院通义MPLUG多模态预训练技术分享,及其在电商等行业的应用实践&#x…...
文章翻译记录
以 PINN 为基础,我们开发了一个框架,用于在不同震源位置和速度模型下进行地震建模。本研究的显著贡献包括: 1. 为了提高网络对不同速度模型的泛化能力,必须将速度变量 vp 作为系统的输入参数。本研究从监督学习中汲取灵感…...

C++ 语法习题(2)
第三讲 循环语句 1.偶数 编写一个程序,输出 1 到 100之间(包括 1 和 100)的全部偶数。 输入格式 无输入。 输出格式 输出全部偶数,每个偶数占一行。 输入样例 No input输出样例 2 4 6 ... 100 参考代码: #include <i…...
使用Gstreamer时遇到WARNING: erroneous pipeline: no element “x264enc“(亲测有效)
WARNING: erroneous pipeline: no element “x264enc” 解决: 我下了gstreamer1.0-plugins-ugly包就解决了 sudo apt install -y gstreamer1.0-plugins-ugly...

SAP 新增移动类型简介
在SAP系统中新增移动类型的过程涉及多个步骤,包括复制现有的移动类型、调整科目设置以及进行必要的测试。以下是新增移动类型的一般步骤和关键点: 复制现有的移动类型: 使用事务代码OMJJ进入移动类型维护界面。 勾选移动类型 这里不填写移动类型,然后直接下…...
SQL性能优化策略
发现问题 通过业务监控发现慢SQL或接口响应延迟。利用性能分析工具定位问题。 定位SQL语句 使用监控工具确定影响性能的SQL语句和表。 SQL查询变慢原因 索引失效:查询未使用索引或索引效率低。多表连接:JOIN操作导致性能下降。查询字段过多…...
代码随想录第四十八天 | 198.打家劫舍, 213.打家劫舍II,337.打家劫舍III
198.打家劫舍 看完想法:这里的偷/不偷,和背包问题中的放/不放感觉是一个道理,所以在dp递推公式中仍旧使用max(dp[i-2] nums[i], dp[i-1]) int rob(vector<int>& nums) {vector<int> dp(nums.size()1,0);if(nums.size()0) …...
C#实用的工具类库
Masuit.Tools Masuit.Tools大都是静态类,加密解密,反射操作,树结构,文件探测,权重随机筛选算法,分布式短id,表达式树,linq扩展,文件压缩,多线程下载…...

首席数据官CDO证书报考指南:方式、流程、适考人群与考试难度
在信息泛滥的今天,数据已转变为企业不可或缺的宝贵资源。 面对海量的信息,如何提炼出价值,为企业带来实质性的收益?首席数据官(CDO)认证的出现正是为了满足这一需求,它不仅是个人专业能力的体现…...

数据库基础复习
数据库简介 关系型数据库:Mysql 、Oracle 、SqlServer.... DB2 达梦 非关系型数据库:Redis 、MongoDB... MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,属于 Oracle 旗下产品。MySQL 是最流行的关系型数据库管…...

探索AI大模型(LLM)减少幻觉的三种策略
大型语言模型(LLM)在生成文本方面具有令人瞩目的能力,但在面对陌生概念和查询时,它们有时会输出看似合理却实际错误的信息,这种现象被称为“幻觉”。近期的研究发现,通过策略性微调和情境学习、检索增强等方…...

【北京迅为】《i.MX8MM嵌入式Linux开发指南》-第一篇 嵌入式Linux入门篇-第十三章 Linux连接档
i.MX8MM处理器采用了先进的14LPCFinFET工艺,提供更快的速度和更高的电源效率;四核Cortex-A53,单核Cortex-M4,多达五个内核 ,主频高达1.8GHz,2G DDR4内存、8G EMMC存储。千兆工业级以太网、MIPI-DSI、USB HOST、WIFI/BT…...

鸿蒙语言基础类库:【@ohos.uri (URI字符串解析)】
URI字符串解析 说明: 本模块首批接口从API version 8开始支持。后续版本的新增接口,采用上角标单独标记接口的起始版本。开发前请熟悉鸿蒙开发指导文档:gitee.com/li-shizhen-skin/harmony-os/blob/master/README.md点击或者复制转到。 导入…...
JavaScript---new Map()用法
new Map 创建 Map 对象设置键值对获取值检查键是否存在键值对数量删除键值对清空所有键值对迭代 Map 在JavaScript中,Map 是一个构造函数,用于创建 Map 对象,它可以存储键值对集合。与普通的对象不同,Map 的键可以是任何类型的值&…...
【数据基础】— 基于Go1.19的站点模板爬虫的实现
目录 1. 定义目标站点 2. 使用Go的库 3. 发送HTTP请求 4. 解析HTML并提取数据 5. 存储数据 6. 并发处理 示例代码 基于Go 1.19的站点模板爬虫实现通常涉及几个关键步骤:定义目标站点、解析HTML页面、提取所需数据、存储数据以及可能的并发处理。下面我将详细…...
Vim 调用外部命令学习笔记
Vim 外部命令集成完全指南 文章目录 Vim 外部命令集成完全指南核心概念理解命令语法解析语法对比 常用外部命令详解文本排序与去重文本筛选与搜索高级 grep 搜索技巧文本替换与编辑字符处理高级文本处理编程语言处理其他实用命令 范围操作示例指定行范围处理复合命令示例 实用技…...
椭圆曲线密码学(ECC)
一、ECC算法概述 椭圆曲线密码学(Elliptic Curve Cryptography)是基于椭圆曲线数学理论的公钥密码系统,由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA,ECC在相同安全强度下密钥更短(256位ECC ≈ 3072位RSA…...
Cesium1.95中高性能加载1500个点
一、基本方式: 图标使用.png比.svg性能要好 <template><div id"cesiumContainer"></div><div class"toolbar"><button id"resetButton">重新生成点</button><span id"countDisplay&qu…...

高频面试之3Zookeeper
高频面试之3Zookeeper 文章目录 高频面试之3Zookeeper3.1 常用命令3.2 选举机制3.3 Zookeeper符合法则中哪两个?3.4 Zookeeper脑裂3.5 Zookeeper用来干嘛了 3.1 常用命令 ls、get、create、delete、deleteall3.2 选举机制 半数机制(过半机制࿰…...

CentOS下的分布式内存计算Spark环境部署
一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架,相比 MapReduce 具有以下核心优势: 内存计算:数据可常驻内存,迭代计算性能提升 10-100 倍(文档段落:3-79…...
浅谈不同二分算法的查找情况
二分算法原理比较简单,但是实际的算法模板却有很多,这一切都源于二分查找问题中的复杂情况和二分算法的边界处理,以下是博主对一些二分算法查找的情况分析。 需要说明的是,以下二分算法都是基于有序序列为升序有序的情况…...
css3笔记 (1) 自用
outline: none 用于移除元素获得焦点时默认的轮廓线 broder:0 用于移除边框 font-size:0 用于设置字体不显示 list-style: none 消除<li> 标签默认样式 margin: xx auto 版心居中 width:100% 通栏 vertical-align 作用于行内元素 / 表格单元格ÿ…...

Map相关知识
数据结构 二叉树 二叉树,顾名思义,每个节点最多有两个“叉”,也就是两个子节点,分别是左子 节点和右子节点。不过,二叉树并不要求每个节点都有两个子节点,有的节点只 有左子节点,有的节点只有…...

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中,新增了一个本地验证码接口 /code,使用函数式路由(RouterFunction)和 Hutool 的 Circle…...
Hive 存储格式深度解析:从 TextFile 到 ORC,如何选对数据存储方案?
在大数据处理领域,Hive 作为 Hadoop 生态中重要的数据仓库工具,其存储格式的选择直接影响数据存储成本、查询效率和计算资源消耗。面对 TextFile、SequenceFile、Parquet、RCFile、ORC 等多种存储格式,很多开发者常常陷入选择困境。本文将从底…...