前言
多态是C++面向对象编程(OOP)的具体体现之一,整个运作体系基于继承。因此,想要系统地学习多态,必须要了解并掌握继承。
概念
多态的作用类似于咱们不同人的买票政策:军人优先,儿童半价,成人全价等。
上述例子中,很好地诠释了多态的作用:用的是同一个系统(类),但面对不同情况的身份(对象),却可以产生多种对应的结果。
多态的定义及实现
要构成多态,还需包含以下两条件:
- 用父类的引用或指针调用基函数
- 父类实现多态的函数必须是
虚函数
, 派生类必须对该函数进行重写/重新实现
2.1虚函数
被virtual
修饰的函数便是虚函数
class Animal
{
virtual void Sound()
{}
};
2.2虚函数的重写
- 在子类对父类的虚函数进行重新实现即为虚函数的重写。
- 子类的返回值类型,参数列表,函数名必须与父类一致。
class Person
{
virtual void BuyTicket()
{
cout << "成人-全价" << endl;
}
}
class Child : public
{
virtual void BuyTicket() // 返回值类型,参数列表,函数名必须与父类一致
{
cout << "儿童-半价" << endl; // 对父类的虚函数进行重写
}
}
2.3虚函数重写的两个例外
2.3.1 协变(基类与派生类返回值类型不同):
C++允许父类返回父类类型的指针/引用,子类返回子类的指针或引用(了解)
class A
{
public:
virtual A* Func() { return new A; }
};
class B
{
public:
virtual B* Func() { return new B; }
};
2.3.2. 析构函数的重写
如果父类的析构函数是虚函数,那么子类的析构函数就构成重载,因为析构函数的名字在编译的时候会被统一换成destructor
。这时候,父类和子类的析构函数同名,满足多态的条件,所以就构成了虚函数重写。
析构函数的调用顺序:子类——>父类
构造函数的调用顺序:父类——>子类
2.4 C++11的 override 和 final
从上面可以看出,构成多态的要求是十分严格的,哪怕是一丁点的字符写错,都不能构成。
有人说,编译器会报错的,很容易就能解决。我们要知道,多态的语法是在编译的时候才检查的,报错不是实时的,如果遇到了一些大项目需要编译很久,如果在这方面出错的话会浪费很多时间。所以,C++11引入了这两个函数…
-
final:修饰虚函数,表示该虚函数不能再被重写
-
override: 检查派生类虚函数是否正确地重写了基类某个虚函数,如果没有重写(重写的不正确)编译报错
override
要放在子类函数- 这里检查了子类的函数,子类的函数签名多接受了一个int类型的参数,直接报错