多态指的是 父类和子类在执行相同行为的时候,出现了不同的结果。而虚函数是实现多态的重要条件之一。下面以Person类和Student类来了解多态。
- class Person {
- public:
- virtual void BuyTicket() { cout << "买票-全价" << endl; }
- };
-
- class Student : public Person {
- public:
- // 子类的 virtual 可以不写,但是父类的必须写
- virtual void BuyTicket() { cout << "买票-半价" << endl; }
- };
目录
多态指的是 父类和子类在执行相同行为的时候,出现了不同的结果。成人和学生执行买票这种行为的时候,成人的结果是全票,学生的结果是半票。
实际上为了从语言的角度达到上述效果,其实就是父类Person 和子类Student 有着相同的成员函数 BuyTicket,父类去调用 BuyTicket 的结果是买全票,子类去调用 BuyTicket 的结果是买半票。我们的第一想法可能是这样
- Person p;
- p.BuyTicket(); // 成人买票
-
- Student s;
- s.BuyTicket(); // 儿童买票
但是这样的灵活性不强,于是引入了多态的概念,仅仅使用一个对象,就可以达到两种效果。
- void Func(Person& p)
- {
- p.BuyTicket();
- }
-
- int main(){
- Person ps;
- Student st;
-
- Func(ps); // 传递Person对象买成人票
- Func(st); // 传递Student对象买半票
- }
在继承中要构成多态需要满足两个条件:
被 virtual 修饰的类成员函数称为 虚函数,这里的 virtual 跟之前虚继承里用到的 virtual 虽然是一个关键字,但是两者没有任何联系。
要重写虚函数需要满足一定的条件。既然是要让子类的某个函数来覆盖父类原本的函数,那就至少要求,子类的某个函数和父类的某个函数长得一模一样,这样才叫重写。
虚函数重写条件:派生类有一个函数跟基类完全相同的虚函数。(函数名、形参、返回值相同)
大前提是两者有继承关系,然后是两个类有完全相同的虚函数(其实子类不加virtual也可)
- class Person {
- public:
- virtual void BuyTicket() { cout << "买票-全价" << endl; }
- };
-
- class Student : public Person {
- public:
- // 子类的 virtual 可以不写,但是父类的必须写
- virtual void BuyTicket() { cout << "买票-半价" << endl; }
- };
下面有两种特殊情况即便是不满足上述条件也构成虚函数重写
协变指的是 基类和派生类的两个虚函数的返回值可以不同,但是返回值必须满足两个条件:
- class Person {
- public:
- virtual Person* BuyTicket() { cout << "买票-全价" << endl; }
- };
-
- class Student : public Person {
- public:
- virtual Student* BuyTicket() { cout << "买票-半价" << endl; }
- };
如果基类的析构函数为虚函数,无论是否加 virtual 关键字,都与基类的析构函数构成重写。
- class Person {
- public:
- virtual ~Person() { }
- };
-
- class Student : public Person {
- public:
- virtual ~Student() { } // 与派生类的析构函数构成重写(子类的 virtual 可以不写)
- };
这是因为编译器对析构函数的名称进行了特殊处理,编译后析构函数的名称统一处理成 destructor