c++进阶之多态
一.概念以及分类
运行时(动态)多态:多个不同种类的对象在运行某个相同接口(功能)时,构成的不同结果,达到不同的状态,就叫做动态多态。
eg:
编译时(静态)多态:主要是函数模板或是函数重载,可传不同参数,得到不同结果,进而达到不同状态。由于实参传给形参在编译阶段,所以叫做编译时多态。
由于把编译时归为静态,执行时归为动态,所以才有了动态多态和静态多态之分。
二.虚函数
前面菱形继承中为解决二义性与冗余,在父类继承方式前,也有添加virtual,那这里的virtual和菱形继承里的有什么关系吗?答案是没有。virtual算一鱼两吃,能代表不同意思。
三.定义以及实现
1.定义
2.多态满足的必要条件
①.必须用引用或指针调用虚函数。
②.被调用的函数必须是虚函数,且派生类必须对基类虚函数进行重写。
重写:
基类虚函数和其对应的派生类虚函数的返回值类型,函数名,参数列表(形参类型,个数,顺序)必须完全相同,函数体可不相同。
我将举一下代码的例子,带大家在代码中明白上面段落的含义。但在查看代码前,先对调用虚函数时的传参规则进行明晰,也是对上一章继承篇中赋值兼容转换的一个复习。
赋值兼容转换:
对于指针,也是如此。
Func函数中,ptr这个基类指针形参,既可以传指向基类的指针,也可以传指向派生类的指针(赋值兼容转换)。通过控制指针的指向,进而调用不同类的虚函数,最终实现不同状态。
#include<iostream> using namespace std; class person { public: virtual void Buyticket() { cout << "全价" << endl; }//子类和父类对应虚函数需要返回值,函数名相同,函数内容可不同。 }; class student : public person { public: virtual void Buyticket(){ cout << "半价" << endl; } }; //利用基类指针对不同类虚函数进行调用,以实现多态。 //通过控制传给基类形参的实参类型,进而调用不同类里的虚函数,这里传参还用到了赋值兼容转换,即把派生类赋值给子类 void Func(person* ptr)//用指针调用虚函数 { ptr->Buyticket(); } int main() { person p; student s; Func(&p); Func(&s); return 0; }注意:1.基类虚函数的virtual不能去掉,去掉以后就无法满足多态了。但在派生类的虚函数里,virtual是能去掉的,虽然不规范,但依旧能满足重写。
2.不同派生类间也能构成多态:
3.特殊语法——析构函数的重写
语法
如果基类,派生类的析构函数名字不同,均带有virtual,那么两个析构函数也能满足多态。
原理
若基类和派生类的析构函数带上了virtual,则系统会将两个析构函数的函数名特殊处理成destructor(函数名就相同了),那么基类和派生类的析构就构成了多态(派生类的析构构成了重写)。
产生该语法的原因(为什么基类析构建议设计为虚函数)
这么设置是为了服务于下面这个情景:
注:delete的底层是ptr->destructor+ operator delete(free)
先做个假设:A,B的析构不满足多态关系。那么delete时,ptr是什么类型的指针,就会去调用什么类的析构。此时,p1,p2全是基类A*类型的指针,就会全去调用A类的析构;但是p2身在曹营心在汉,虽然是A*类的指针,但指向B类的空间,A类的析构释放不掉B类的空间,就会造成空间的泄漏。
那如果满足多态关系,delete时,究竟调用哪个类的析构(destructor),这是由指向空间的类型所决定的。
4.override和final关键字
override
final
5.重载/重写/隐藏的对比
常考,重点!!!!!!!!
注:隐藏也叫重定义。
6.纯虚函数和抽象类
四.多态的原理
1.虚函数表指针
先通过一道老六题引入虚函数表指针这个概念:
注:指针所占大小与其指向内容无关,与系统位数有关。32位下,指针占4字节;64位下,指针占8字节。
被老六肘击的一幕
读完题目,咳,这不是考内存对齐吗?so easy, int4个字节,char1个字节,对齐3个字节,一共8字节,选C。
but.....man,what can I say?!
正解
让我们调用监视窗口:
在b这个对象的构成里,潜藏着一个虚函数表指针,就是我们接下来要探讨的东西。
虚函数表指针
从上图我们可以看出,b的成员还包括一个指针__vfptr,该指针指向一片区域,该区域存储类里所有虚函数的地址。由此,我们可以看出,虚函数表就是指那片区域,是个存放类里所有虚函数地址的数组。而指针__vfptr指向虚函数表,所以它就叫虚函数表指针。
2.多态的原理
借助虚函数表指针这个概念,我们来剖析多态的原理。
多态里生成一种状态的底层原理流程:
注:
杭哥的图,同一个意思:
综上:当传不同对象,经以上流程,生成不同状态,就构成了多态。