1. 多态的概念
多态的概念:通俗来说,就是多种形态,具体点就是去完成某个行为,当不同的对象去完成时会产生出不同的状态
举个例子,对于买票这个行为,当普通人买票时就是全价买票,学生买票就是半价,军人买票就是优先买票。这就是不同的对象执行容易个行为的时候,会有不同的状态产生。
再有一个例子,我们知道有种东西叫做大数据杀熟,这就是通过分析你的以往的行为,给使用者分为几个不同的类型,对于不同的使用者,做买东西这个行为,定价不同。这也是一种多态行为
2.多态的定义和实现
1. 虚函数
1. 虚函数的概念
使用virtual修饰的类成员函数叫做虚函数
class person { public: virtual void BuyTicket() { cout << "买票-全价" << endl; }//虚函数 };
2. 虚函数的重写
我们知道,当基类和派生类中的成员函数重名的时候,会构成隐藏(重定义),其中,如果重名函数的返回值类型和参数列表完全相同,并且都是虚函数时,将会构成虚函数的重写。
class person { public: virtual void BuyTicket() { cout << "买票-全价" << endl; } }; class student : public person { public: virtual void BuyTicket() { cout << "买票-半价" << endl; }//写法一 //void BuyTicket() { cout << "买票-半价" << endl; }//写法二 };
其中person和student中的BuyTicket函数就构成了重写。
在上述student类中的BuyTicket函数还有写法二,使用写法二这种写法也是构成重写的。
✅原因:在重写基类虚函数的时候,派生类的虚函数不加virtual关键字也可以构成重写,这是因为在继承后基类的虚函数被继承下来任然保持着虚函数属性,也可以理解成:在重写的时候,只关注函数体的实现。函数返回值类型、函数名和参数列表的要求只是为了保证能够构成重写。为了规范写法,我们这里还是建议派生类的虚函数也加上virtual关键字。
3. 构成虚函数重写的两个例外
1、析构函数的重写
如果基类的析构函数为虚函数,此时派生类析构函数只要定义,无论是否加virtual关键字,都与基类的析构函数构成重写,虽然基类与派生类析构函数名字不同。虽然函数名不相同,看起来违背了重写的规则,其实不然,这里可以理解为编译器对析构函数的名称做了特殊处理,编译后析构函数的名称统一处理成destructor
2、协变:基类和派生类虚函数返回值不同
派生类重写基类虚函数的时候,改变了返回值的类型。即基类虚函数返回基类类型的指针或引用,派生类返回派生类的指针或引用也构成重写
2. C++11 override和final
可以看到,C++对函数重写的要求比较严格,但是在某些情况下很容易忽略,导致无法构成重写,但是这种错误在编译期间不会被报出,最终运行结果却会和预期不同,后期再debug就很麻烦,所以C++11提供了override和final两个关键字用于检测是否重写。
1. final关键字
final修饰虚函数,表示该虚函数不能再被重写
class Car { public: virtual void Drive() final {} }; class Benz : public Car { public: virtual void Drive() { cout << "Benz" << endl; } };
final的另一个作用:创建一个不能被继承的类
2.override关键字
override:检查派生类虚函数是否重写了基类的某个虚函数,如果没有重写则编译报错,如果重写了正常运行
class Car { public: virtual void Drive() {} }; class Benz : public Car { public: virtual void Drive(int a) override { cout << "Benz" << endl; } };