多态的定义
定义:同一种行为对于不同的对象,有不同的表现
例如:进行MOBA类游戏来说,所有玩家都有选择英雄这一操作,但是选择的英雄却不一样。
多态的分类
多态分为两类:
静态多态:基于函数重载,和泛型编程去实现。(直接通过派生类去调用函数)
void fun_1(B &a)
{
a.function();
}
void fun_2(B &a)
{
a.function();
}
int main()
{
B first;
B second;
fun_1(first);
fun_2(second);
}
优点:简单易懂,写起来不用动脑筋。
缺点:维护升级难度大,每个派生类都需要单独的一个函数,如果项目再创建一个新的派生类,又 需要再写一遍函数。
动态多态:基于virtual函数去实现。(可以作为函数接口,传入参数后会通过virtual函数选择调用哪个派生类的函数)
优点:不需要写多个函数,将一个函数作为接口就行。
缺点:个人感觉没有缺点,硬要说可能就是会涉及到更多知识点,比如引用和virtual之类的。
virtual函数
virtual函数即虚函数,使用virtual关键字声明的函数,是实现动态多态的基础。我们使用时需要注意几个条件:
1:非类的成员函数不能定义为虚函数(全局的函数);
2:类的静态成员函数不能定义为虚函数(因为被static修饰的成员函数和成员变量就不在属于具体对象,而属于类);
3:构造函数不可以定义为虚函数,但析构函数可以(而且比较推荐);
注:基类的某一成员函数声明为虚函数时,子类同名的函数也会自动变为虚函数;
写法如下:(切记是在类中的函数)
virtual的作用:
当我们在想调用派生类的函数时,不用在通过子类去访问,而是可以通过父类的虚函数访问,由与成员函数的覆盖规则,会自动调用子类的虚函数。
void fun_1(A &a)
{
a.function();
}
int main()
{
B first;
B second;
fun_1(first);
fun_1(second);
}
至于他为什么会覆盖,这里就涉及到虚函数的原理——虚函数表:
一旦类中引入了 虚函数,在程序编译期间就会创建虚函数表,表中每一项数据都是虚函数的入口地址。为了将对象与虚函数表关联起来,编译器会在对象中会增加一个指针成员用于存储虚函数表的位置。基类的指针指向派生类对象时就是通过虚函数表的指针来找到实际应该调用的函数。而基类与派生类都维护自己的虚函数表,如果派生类重写基类的虚函数,则虚函数表存储的是派生类的函数的地址(有重名的虚函数,就会覆盖),没有重写的虚函数则保存的是基类的虚函数表。