这篇文章和大家一起学习一下c++中的多态
多态的概念
多态的概念:通俗来讲,就是多种形态。多态分为编译时多态(静态多态)和运⾏时多态(动态多态)。
什么是静态多态
前⾯讲的函数重载和函数模板,它们传不同类型的参数就可以调用不同的函数,通过参数不同从而达到多种形态,之所以叫编译时多态,是因为它们实参传给形参的参数匹配是在编译时完成的,而编译时一般归为静态,运行时归为动态
什么是动态多态
具体点就是去完成某个⾏为(函数),可以传不同的对象就会完成不同的⾏为,就达到多种形态。
多态的定义及实现
构成条件
多态是继承关系下的类对象,去调用不同的函数,产生不同的行为。
实现多态的两个重要条件
必须指针或者引⽤调⽤虚函数
被调⽤的函数必须是虚函数。
虚函数的定义
类成员函数前⾯加virtual修饰,那么这个成员函数被称为虚函数。
上图的函数就是虚函数
虚函数的重写(覆盖)
派⽣类中有⼀个跟基类完全相同的虚函数(即派⽣类虚函数与基类虚函数的返回值类型、函数名字、参数列表完全相同),称派⽣类的虚函数重写了基类的虚函数。
需要注意的是:在重写基类虚函数时,派⽣类的虚函数在不加virtual关键字时,虽然也可以构成重写(因为继承后,基类的虚函数也被继承了下来,并且在基类中依旧保持虚函数的属性),但不建议这么玩
class Person
{
public:
virtual void BuyTicket() { cout << " 买票 全价 " << endl; }
};
class Student : public Person
{
public:
virtual void BuyTicket() { cout << " 买票 打折 " << endl; }
};
void Func(Person* ptr)
{
// 这⾥可以看到虽然都是 Person 指针 Ptr 在调⽤ BuyTicket
// 但是跟 ptr 没关系,⽽是由 ptr 指向的对象决定的。
ptr->BuyTicket();
}
int main()
{
Person ps;
Student st;
Func(&ps);
Func(&st);
return 0;
}
虚函数重写的⼀些其他问题(了解)
派⽣类重写基类虚函数时,与基类虚函数返回值类型不同。即基类虚函数返回基类对象的指针或者引⽤,派⽣类虚函数返回派⽣类对象的指针或者引⽤时,称为协变。
总结:各自(类)虚函数返回各自(类)对象的指针或应用
析构函数的重写
基类的析构函数为虚函数,此时派⽣类析构函数只要定义,⽆论是否加virtual关键字,都与基类的析 构函数构成重写,虽然基类与派⽣类析构函数名字不同看起来不符合重写的规则,实际上编译器对析 构函数的名称做了特殊处理,编译后析构函数的名称统⼀处理成destructor,所以基类的析构函数加了 vialtual修饰,派⽣类的析构函数就构成重写。
总结:1. 基类的析构函数是虚函数
2. 派生类析构函数与基类析构函数构成重写
override 和final关键字
C++对函数重写的要求⽐较严格,但是有些情况下由于疏忽,⽐如函数名写错参数写 错等导致⽆法构成重载,⽽这种错误在编译期间是不会报出的,只有在程序运⾏时没有得到预期结果 才来debug会得不偿失,因此C++11提供了override,可以帮助⽤⼾检测是否重写。如果我们不想让派 ⽣类重写这个虚函数,那么可以⽤final去修饰。
纯虚函数和抽象类
在虚函数的后⾯写上=0(即virtual void Drive() = 0;),则这个函数为纯虚函数,纯虚函数不需要定义实现(实现没啥意义因为要被 派⽣类重写,但是语法上可以实现),只要声明即可。包含纯虚函数的类叫做抽象类,抽象类不能实例 化出对象,如果派⽣类继承后不重写纯虚函数,那么派⽣类也是抽象类。纯虚函数某种程度上强制了 派⽣类重写虚函数,因为不重写实例化不出对象。
总结:1. 纯虚函数:在虚函数的后面加上=0即可
2. 纯虚函数不需要定义实现,只要声明即可
3. 抽象类:含有纯虚函数的类
4. 抽象类不能实例化出对象
5. 派生类继承后不重写纯虚函数,这个派生类也是抽象类
多态的原理
除了_b和_ch成员,还多⼀个__vfptr放在对象的前⾯(注意有些平台可能 会放到对象的最后⾯,这个跟平台有关),对象中的这个指针我们叫做虚函数表指针(v代表virtual,f代 表function)。⼀个含有虚函数的类中都⾄少都有⼀个虚函数表指针,因为⼀个类所有虚函数的地址要 被放到这个类对象的虚函数表中,虚函数表也简称虚表。
制作不易,给个三联吧,谢谢啦