文章目录
- 一、什么是多态
- 二、构成多态的条件
- 2.1什么是虚函数
- 2.1如何构成虚函数的重写(原理层面上叫:重写)
- 2.2父类指针的调用
- 三、多态调用父类指针出现的情况
- 四、构成多态的一种特殊情况(协变)
- 五、析构函数构成的多态
- 六、多态的原理
- 七、多态的静态绑定和动态绑定
- 7.1多态的静态绑定
- 7.2多态的动态绑定
- 八、单继承和多继承的虚函数表
- 九、菱形虚拟继承
- 十、override和final
- 10.1override是检查派生类虚函数是否重写了基类的虚函数如果没有重写就编译报错
- 10.2final是标明该虚函数不能重写
- 十一、抽象类
先赞后看,养成习惯!!!^ _ ^<3 ❤️ ❤️ ❤️
码字不易,大家的支持就是我坚持下去的动力。点赞后不要忘了关注我哦!
所属专栏:C++进阶
一、什么是多态
通俗来讲多态就是完成某一种行为,不同的对象会完成会产生不同的状态。
比如买票,针对不同的人群有不同的购票机制,对于儿童来说怎么样,对于大学生来说怎么样,这就是不同人群产生的不同状态机制
二、构成多态的条件
1.首先需要继承关系
2.然后就要构成虚函数的重写
3.接着需要用父类的指针或者引用去调用虚函数
2.1什么是虚函数
通过前面的虚拟继承我们得知在继承的父类前面加一个virtual就行了,那么虚函数也是如此,在普通函数前面加一个virtual就行了
2.1如何构成虚函数的重写(原理层面上叫:重写)
1.父类的虚函数和子类的虚函数的返回值,函数名,参数类型都必须相同
2.父类的虚函数必须加上virtual,子类可以加可以不加,不加virtual,但是返回值,函数名,参数类型都必须与父类相同,这样叫接口继承(也就是把父类的虚函数除了实现全部变成了子类的)
2.2父类指针的调用
三、多态调用父类指针出现的情况
指针指向谁就调用谁的函数
这里调用的是子类的虚函数
这里调用的是父类的虚函数
四、构成多态的一种特殊情况(协变)
协变构成的条件是:
父类和子类的函数的返回值不同,父类返回的是某个父类的指针,子类返回的是某个子类的指针,函数名和参数类型相同
五、析构函数构成的多态
由于编译器的特殊处理,虚函数的函数名都被处理为destructor
六、多态的原理
在描述原理之前,我们先看一个问题
这里打印的结果是多少呢?
我们首先考虑的是内存对齐的规则首先想到的肯定是8,但是这里打印的是12
为什么呢?我们来看看监视窗口的情况
这里我们发现出现了一个指针,为什么会有这个指针呢?
其实这个指针叫做虚函数表指针(虚表指针),用来存储虚函数表(虚表指针)的,也就是说虚函数的地址是存在虚函数表中的
同时也引发了另一个问题:虚函数表又是什么?
虚函数表实际上是虚函数指针数组,里面存储的是虚函数的地址,从这个地址中可以找到虚函数。
七、多态的静态绑定和动态绑定
7.1多态的静态绑定
静态绑定又称为前期绑定,也就是程序在编译的时候就已经确定了程序的行为,也称为静态多态
比如函数重载
7.2多态的动态绑定
动态绑定又称为后期绑定,也就是程序在运行的期间,根据具体拿到的类型进行确定程序的行为,调用具体的函数,也称为动态多态
八、单继承和多继承的虚函数表
这里我们需要关注的是多继承的虚函数表,因为刚刚单继承的虚函数表已经研究过了,这里不过多赘述
这里我们可以看到在监视窗口并无法观察到派生类的所有虚函数的地址情况,所以我们写一个程序来观察派生类的所有虚函数的地址
这里VS在每个虚函数表指针中的末尾都加了一个nullptr,我们利用这个特性打印出base中virtual func3和virtual func4存在哪一个虚表中
由于谁先继承相等于谁先声明,先声明的先打印,后继承的后打印。我们可以看到如图:
明显可以看出存在先声明的A中的虚表中
九、菱形虚拟继承
通过最下面的C的虚表指针的地址可以判断出A和B中的虚表指针在每个父类的第一行
十、override和final
10.1override是检查派生类虚函数是否重写了基类的虚函数如果没有重写就编译报错
10.2final是标明该虚函数不能重写
十一、抽象类
包含纯虚函数的类叫做抽象类,抽象类无法实例化出对象,继承了抽象类的派生类也是抽象类