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

继承超详细介绍

一 、继承

1 继承的概念

继承是面向对象程序设计使得代码可以复用的最重要手段,它使得我们可以在原有类的特性的基础上进行扩展,增加方法和属性(成员函数与成员变量),这样产生新的类,叫作派生类。继承呈现了面向对象程序设计的层次结构,体现了由简单到复杂的认知过程。以前我们学习的实在函数上的复用,现在我们一起来学习在类上的复用吧!

1. 样例示范 

下面我们设计两个类,一个是Student类,一个Teacher类

可以看到,这两个类中有大量重复的如姓名,地址等的成员变量,设计到两个类里面是冗余的,当然他们 也有⼀些不同的成员变量和函数,比如老师独有成员变量是职称,学生的独有成员变量是学号,但是如果我们能定义一个新类,叫Person类,将这些冗余的成员变量放进去,然后通过某种方式使得Student类和Teacher类能获得这些成员变量,那就使得复用率大大提高,这种方式就是继承。

2 继承定义

1.定义格式: 派生类类名 :继承方式  基类

 Student就是派生类类名 , 继承方式是public  , 基类(父类)是Person

2.继承方式

(1)                

(2)继承访问方式的变化

  1.  基类private成员在派生类中无论以什么方式继承都是不可⻅的。这⾥的不可见是指基类的私有成员 还是被继承到了派⽣类对象中,但是语法上限制派⽣类对象不管在类里面还是类外面都不能去访问它。
  2. 基类private成员在派⽣类中是不能被访问,如果基类成员不想在类外直接被访问,但需要在派⽣类 中能访问,就定义为protected。可以看出保护成员限定符是因继承才出现的
  3. 实际上⾯的表格我们进⾏⼀下总结会发现,基类的私有成员在派⽣类都是不可⻅。基类的其他成员 在派⽣类的访问⽅式==Min(成员在基类的访问限定符,继承⽅式),public >protected> private
  4. 使⽤关键字class时默认的继承⽅式是private,使⽤struct时默认的继承⽅式是public,不过最好显 ⽰的写出继承⽅式。
  5. 在实际运⽤中⼀般使⽤都是public继承,⼏乎很少使⽤protetced/private继承,也不提倡使⽤ protetced/private继承,因为protetced/private继承下来的成员都只能在派⽣类的类⾥⾯使⽤,实 际中扩展维护性不强

3 基类与派生类之间的转化

3.1 public继承的派生类对象可以赋值给基类的指针或者基类的引用,这里有个形象的说法叫做切片,相当于吧派生类中属于基类的那一部分切割出来,给到基类的指针或者基类的引用(注意只有public继承才行)(注意这里没有隐式类型转化)

样例:

 3.2 基类不能赋值给派生类

3.3 基类的指针和引用可以通过强制类型转换给派生类的指针和引用 ,但是必须是基类的指针是指向对应的派生类对象时才是安全的

4.继承的作用域 

 规则:

  1. 在继承中,基类和派生类都有其单独的作用域
  2. 基类和派生类中有同名成员(成员变量/成员函数),派生类将屏蔽基类的实现,只调用派生类的实现,这里叫做隐藏/重定义(注意这里不是函数的重载了,函数的重载必须在相同作用域
  3. 查找规则:由于隐藏,查找先找子类 -> 父类 -> 全局域(从这里也能看出,基类的成员函数并不是在派生类中重新写一个,而是子类找不到去父类里找,更何况如果是写到子类里,那就有两个同名函数在同一作用域里,编译语法不过的)
  4. 隐藏规则:注意这里只要函数名相同,就构成隐藏关系(在派⽣类成员函数中,可以使⽤基类::基类成员显⽰访问基类成员)

样例:

1.

2.

这样编译不过,因为只要函数名相同就构成重写,只能访问到子类的fun().

5 派生类的默认成员函数

5.1  四个常用的默认成员函数

6个默认成员函数,默认的意思就是指我们不写,编译器会变我们⾃动⽣成⼀个,那么在派⽣类中,这 ⼏个成员函数是如何⽣成的呢?

(1)构造函数

  1. 派生类的实例化过程,是先创建父类,再创建子类,因为在子类初始化的过程可能会用到父类的成员
  2. 派生类的构造过程必须先调用基类的构造函数初始化基类的那一部分成员。如果基类没有默认构造函数(你已经显示写了基类的构造函数),则必须在派生类的初始化列表阶段显示调用基类的构造函数

示例:

1.Person调用默认构造

2. Person构造显示调用

若此时没有显示调用基类构造,编译器语法报错 

通过输出发现先调用基类构造,再走派生类初始化列表

此时将st正确初始化

(2)拷贝构造函数

  1. 派生类调用拷贝构造函数必须调用基类的拷贝构造函数
  2. 若是仅涉及浅拷贝,那就不用显示写,使用基类的默认拷贝构造即可
  3. 可若是涉及深拷贝(有资源申请),那就不能让编译器一个一个进行值拷贝了,得显示写基类的拷贝构造函数,在派生类的拷贝构造显示调用基类的拷贝构造

样例:

拷贝构造也是构造,也可以用初始化列表 

 (3)派生类的operator=

  1. 必须调用基类的operator=完成基类的复制。
  2. 需要注意的是派⽣类的 operator=隐藏了基类的operator=,所以显⽰调⽤基类的operator=,需要指定基类作⽤域

(4)析构函数 

  1. 首先,在对象的析构中,派生类的析构函数会在被调⽤完成后自动调用基类的析构函数清理基类成员。因为这样才能保证派生类对象先清理派生类成员再清理基类成员的顺序。
  2. 没有资源申请,不用显式写
  3. 因为多态中⼀些场景析构函数需要构成重写,重写的条件之⼀是函数名相同(这个我们多态章节会讲解)。那么编译器会对析构函数名进行特殊处理,处理成destructor(),所以基类析构函数不加 virtual的情况下,派生类析构函数和基类析构函数构成隐藏关系。

6.实现一个不能被继承的类 

方法1:基类的构造函数私有,派生类的构成必须调用基类的构造函数,但是基类的构成函数私有化以后,派生类看不见就不能调用了,那么派生类就无法实例化出对象。

方法2:C++11新增了⼀个final关键字,final修改基类,派⽣类就不能继承了。

示例:

直接在基类的类名后加final关键字即可 

7 继承和友元以及静态成员

1.继承和友元

友元不能继承,基类的友元不是子类的友元,也就是说基类友元不能访问派生类私有和保护成员

2.继承与静态成员

基类定义了static静态成员,则整个继承体系⾥⾯只有⼀个这样的成员。无论派生出多少派生类,都只有一个static成员

8.菱形继承

1.继承模型

再说菱形继承之前,先说一下继承的分类,继承可以分为单继承与多继承

单继承:⼀个派生类只有⼀个直接基类时称这个继承关系为单继承,我们之前写的全是单继承

多继承:⼀个派⽣类有两个或以上直接基类时称这个继承关系为多继承,多继承对象在内存中的模型 是,先继承的基类在前⾯,后⾯继承的基类在后⾯,派生类成员在放到最后面

菱形继承:菱形继承是一种多继承

菱形继承是多继承的⼀种特殊情况。菱形继承的问题,从下⾯的对象成员模型构造,可以 看出菱形继承有数据冗余和⼆义性的问题,在Assistant的对象中Person成员会有两份 

需要显⽰指定访问哪个基类的成员可以解决⼆义性问题,但是数据冗余问题⽆法解决

这就引入了虚继承

9.虚继承

很多⼈说C++语法复杂,其实多继承就是⼀个体现。有了多继承,就存在菱形继承,有了菱形继承就有 菱形虚拟继承,底层实现就很复杂,性能也会有⼀些损失

使用虚继承:问题解决,virtual使用位置在将产生二义性/数据冗余的上一位置

http://www.lryc.cn/news/511021.html

相关文章:

  • wordpress调用指定ID分类下浏览最多的内容
  • 18.springcloud_openfeign之扩展组件二
  • FreePBX修改IP地址和端口以及添加SSL证书开启HTTPS访问
  • 运算符 - 算术、关系、逻辑运算符
  • 大模型-ChatGLM2-6B模型部署与微调记录
  • RDFS—RDF模型属性扩展解析
  • pyqt和pycharm环境搭建
  • salesforce 控制 Experience Cloud 站点用户可以看到哪些用户
  • 【玩转OCR】 | 腾讯云智能结构化OCR在多场景的实际应用与体验
  • 面试题整理20----什么是蓝绿部署、灰度发布、金丝雀发布他们有什么区别?
  • c语言传参数路径太长,导致无法获取参数
  • React性能优化:构建更高效的应用
  • python+PyMuPDF库:(一)创建pdf文件及内容读取和写入
  • vue3配置测试环境、开发环境、生产环境
  • Jsonlizer,一个把C++各类数据转成 Json 结构体的玩意儿
  • Qt仿音乐播放器:设置窗口、部件属性
  • 使用 .NET 6 或 .NET 8 上传大文件
  • 基于特征工程(pca分析)、小波去噪以及数据增强,同时采用基于注意力机制的BiLSTM、随机森林、ARIMA模型进行序列数据预测
  • 攻防世界 PHP2
  • 主板idyy
  • 轻松实现向量搜索:探索 Elastic-Embedding-Searcher 项目
  • flask后端开发(3):html模板渲染
  • 逻辑控制语句
  • [OpenGL]使用 Compute Shader 实现矩阵点乘
  • jangow-01-1.0.1靶机
  • MySQL 查询大偏移量(LIMIT)问题分析
  • Docker、containerd、安全沙箱、社区Kata Containers运行对比
  • 使用npm包的工程如何引入mapboxgl-enhance/maplibre-gl-enhance扩展包
  • 【NIFI】实现ORACLE->ORACLE数据同步
  • 单例模式的写法