2020-C++高级程序设计-C++ 继承
继承
1. 继承机制
- 基于目标代码的复用
- 对事物进行分类
- 派生类是基类的具体化
- 把事务(概念)以层次结构表示出来,有利于描述和解决问题
- 增量开发(面向接口编程)
2. 单继承
- protected:
- 如果没有继承的话,protected和private是相同的
- 派生类可以访问基类中protected的属性的成员。
- 派生类不可以访问基类中的对象的protected的属性。
- 派生类含有基类的所有成员变量
2.1. 核心代码示例
1 |
|
2.2. 继承方式
- public、private:访问权限只和基类中的访问权限有关
2.2.1. public
- public:
class Undergraduated_Student: public Student
- 原来的public是public,原来的private是private
- 如果没有特殊需要建议使用public
2.2.2. private
- private:原来所有的都是private,但是这个private是对于Undergraduate_Student大对象而言,所以他自己还是可以访问的。
- 默认的继承方式
2.2.3. protected
- 如果没有继承的话,protected和private是相同的
- 派生类可以访问基类中protected的属性的成员。
- 派生类不可以访问基类中的对象的protected的属性。
- 派生类含有基类的所有成员变量
2.3. 继承声明方式
1 |
|
2.4. 基类和继承类的方法关系
2.4.1. 派生类中的showInfo()
- 派生类中的showInfo():Overwirtten 重写(绝对不是覆盖),隐藏基类的showInfo()函数
- 而并不是覆盖操作
2.4.2. 基类的showInfo()
- 如果基类中有一个
void ShowInfo(int x)
:那么是不是从基类可以进行调用呢?- 不可以(所有函数都被隐藏)
- 因为重定义将名空间进行了覆盖
- 父类中的所有的函数都不可见:但是我们可以通过指定名空间来完成访问:
using Student::showInfo
,所有的版本都可以见,这时候是重写。
2.4.3. 方法调用的顺序
- 首先在名空间中按照名称进行匹配
- 一旦名称匹配,则会校验函数参数
- 匹配不上是不会去别的名空间进行匹配(也就是不会去student那里去匹配)
2.5. 方法覆盖
- 我们需要指明覆盖:
virtual
:在对应想要重写的函数的前面写上一个virtual - 虚函数实现的是多态
2.6. 不可以被继承的部分
- 构造函数和析构函数是不可以被继承的:是对类进行初始化的,无法继承
- 运算符重载函数也是不可以被继承的
2.7. 访问权限的修改方法
1 |
|
- 声明
char nickname[16];
并没有修改可变性,语法无误,语义不对;
3. 继承的初始化
- 派生类对象的初始化
- 由基类和派生类共同完成
- 构造函数的执行次序
- 基类的构造函数
- 派生类对象成员类的构造函数(注意!)
- 派生类的构造函数
- 析构函数的执行次序(与构造函数执行顺序相反)
- 派生类的析构函数
- 派生类对象成员类的析构函数
- 基类的析构函数
- 基类构造函数的调用
- 缺省执行基类默认构造函数
- 如果要执行基类的非默认构造函数,则必须在派生类构造函数的成员初始化表中指出
1 |
|
4. 多继承
4.1. 定义
- 定义
1 |
|
- Java不允许多继承,是因为多继承非常复杂。
- 继承方式:默认是private的继承方式:public、private 、protected
- 继承方式及访问控制的规定同单继承:重复进行继承
- 派生类拥有所有基类的所有成员
- 可以睡的沙发:继承sofa和Bed
- setWeight重名:两个基类有相同部分,我们会拆分基类
- 之后我们拆分出来setWeigth()(Base Class Decomposition)
- 形成菱形结构:还有问题,Weigth变量依旧在,已然有两个Weigth部分
- 解决方案:虚继承
4.2. 基类声明顺序(初始化顺序)
- 基类的声明次序决定:
- 对基类构造函数/析构函数的调用次序(顶部基类,同层基类按照声明顺序) 上图中就是 ABCD的顺序
- 对基类数据成员的存储安排
- 析构函数正好相反
4.2.1. 名冲突
- <基类名>::<基类成员名>
- 成交变量和成员函数的重名问题:在上图中,D中会有B和C的x
- 问题:每次setWeight到底是设置谁的?
4.2.2. 虚基类
- 如果直接基类有公共的基类,则该公共基类中的成员变量在多继承的派生类中有多个副本
- 如果有一个公共的虚基类,则成员变量只有一个副本
- 类D有两个x成员,B::x,C::x
- 虚继承:保留一个虚指针
- 虚指针指向A
- 可以认为是一个组合关系
- 合并
1 |
|
4.2.3. 虚基类注意
- 虚基类的构造函数由最新派生出的类的构造函数调用
- 原来是B构造一份A,C构造一个A
- 而现在是由D调用A的构造函数,在D的时候先调用A的构造函数,在B和C的时候不在调用A的构造函数,而只是存放指针
- 虚基类的构造函数优先非虚基类的构造函数执行
- 如果有两个基类,两个类有一个相同名称的虚函数,比如B和C都有一个同名的虚函数,到底怎么做?不做要求
4.2.4. 多继承理解
- 通过VS的c++命令行中选择打印一些参数
- Ex:
/d1 reportAllClassLayout
,可以看到所有类的布局如下
- 下图是一个逻辑上的理解:会有多个虚函数表
- 构造D,将B的v3覆盖
- 之后在第一个A上面直接添加一个虚函数表中的记录
- 可以分开覆盖,也可以各自覆盖
2020-C++高级程序设计-C++ 继承
https://spricoder.github.io/2020/07/01/2020-C-plus-plus-advanced-programming/C++-OOP/2020-C-plus-plus-advanced-programming-C++%20%E7%BB%A7%E6%89%BF/