C++:深入理解多态
一、多态的概念
多态的概念:通俗来说,就是多种形态,具体点就是去完成某个行为,当不同的对象去完成时会产生出不同的状态。
那究竟多态的实际价值体现在哪里呢??
1、举个例子比如说购买高铁票这个行为,如果是普通人就是原价购买,如果是学生的话就是半价购买,如果是军人的话,可以优先走绿色通道购买……
2、再举个例子比如说大数据杀熟(个人看法,不一定正确,只是为了方便解释多态)
(1)在线支付市场,如果你平时经常用微信而很少用支付宝,那么在支付宝举办一些类似领取红包的活动的时候,他可能会有相关的算法去分析你的账户信息,对于很少用支付宝的用户,可能相对来说得到的红包金额就会更大,这是为了鼓励你去使用支付宝,可能你某一天在商场购物的时候,想起来自己有个红包没用,就会放弃使用微信而转而使用支付宝。同样是扫码动作,不同的用户扫得到的不一样的红包,这也是一种多态行为。
(2)游戏抽卡相信大家也体验过,充钱充的越少的可能反而抽卡的运气会更好,这样会使得你不至于跟氪佬的差距特别大,鼓励你继续玩游戏。而充值充得多可能运气就会越不好,因为你不缺钱,同样是抽卡,不同的玩家抽卡概率不同,这也是一种多态行为。
总而言之就是,我们生活中一件事情不同的群体去做需要有不同的反馈,那这就是多态!!
二、多态的定义和实现
2.1 构成多态的条件
首先多态现象的产生是在继承的基础上产生的。
多态是在不同继承关系的类对象,去调用同一函数,产生了不同的行为。比如Student继承了Person。Person对象买票全价,Student对象买票半价。
构成多态需要以下两个条件(重点):
(1)对父类虚函数的重写->三同(函数名、参数、返回值)
(2)必须是父类的指针或者引用去调用
是否构成多态的不同表现:
1、不满足多态 -- 看调用者的类型,调用这个类型的成员函数
2、满足多态 -- 看指向的对象的类型,调用这个类型的成员函数
满足多态:
不满足多态:
思考:你可能会有这样的疑惑->我直接用在函数体里面用if……else不也可以达到这样的效果吗??为什么非得用多态来完成呢???
——>答:有些场景下必须得用多态才能解决,比如父类的指针或者引用调用析构函数
但是由于父类的指针或引用是可以指向子类的对象的,甚至在某些场景下子类的指针或引用也可以指向父类的对象(前提是父类的对象被子类对象给赋值过) ,如果没有发生多态的话,那么就会去看调用者的类型而不是去看指向对象的类型,从而导致指向对象没有被析构,造成内存泄露。
加了virtual之后,就可以解决这个问题了。
综上我们可以发现,if……else并不能替代多态!!!
2.2 虚函数的重写
虚函数:即被virtual修饰的类成员函数称为虚函数
虚函数的重写(覆盖):派生类中有一个跟基类完全相同的虚函数(即派生类虚函数与基类虚函数的返回值类型、函数名字、参数列表完全相同),称子类的虚函数重写了基类的虚函数。
虚函数重写有两个例外:
(1)协变(返回值可以不同->但是必须是父子关系的指针或者引用(其实不一定是自己的父子类,其他的父子类也行))
class Person { public: virtual Person* f() { return this; } }; class Student : public Person { public: virtual Student* f() { return this; } }; int main() { return 0; }
返回值也可以是其他父子类的指针或者引用,也可以是协变。
class A {}; class B : public A {}; class Person { public: virtual A* f() { return nullptr; } }; class Student : public Person { public: virtual B* f() { return nullptr; } }; int main() { return 0; }
(2)子类的virtual可以省略
因为虚函数的重写本身就是接口继承 我把除函数体以外的全部部分都可以继承下来,然后再去重写继承父类的这个函数的实现 这样只要父类写了virtual就可以了。
我们来看一道经典的题目
class A { public: virtual void func(int val = 1) { std::cout