零、前言
C++有五大特性:对象,封装,继承,抽象和多态。而本章则将学习讲解C++中的多态
一、多态的概念和定义
概念:
通俗来说,就是多种形态,具体点就是去完成某个行为,当不同的对象去完成时会产生出不同的状态
示例:买票
普通人买票时,是全价买票;学生买票时,是半价买票;军人买票时是优先买票
定义:
多态是在不同继承关系的类对象,去调用同一函数,产生了不同的行为
多态构成条件:
必须通过基类的指针或者引用调用虚函数
被调用的函数必须是虚函数,且派生类必须对基类的虚函数进行重写
示图:
二、虚函数
1、概念和定义
- 虚函数语法:
被virtual修饰的类成员函数称为虚函数
- 示例:
class Person { public: virtual void BuyTicket() { cout << "买票-全价" << endl; } };
- 虚函数重写:
派生类中有一个跟基类完全相同的虚函数(即派生类虚函数与基类虚函数的返回值类型、函数名字、参数列表完全相同),称子类的虚函数重写了基类的虚函数
- 示例:
class Person { public: virtual void BuyTicket() { cout << "买票-全价" << endl; } }; class Student : public Person { public: virtual void BuyTicket() { cout << "买票-半价" << endl; } }; void Func(Person& p) { p.BuyTicket(); } int main() { Person ps; Student st; Func(ps); Func(st); return 0; }
2、虚函数重写的特例
- 协变
类虚函数返回基类对象的指针或者引用,派生类虚函数返回派生类对象的指针或者引用时,称为协变(基类与派生类虚函数返回值类型不同)
- 示例:
class A {}; class B : public A {}; class Person { public: virtual A* f() { cout << "virtual A* f()" << endl; return new A; } }; class Student : public Person { public: virtual B* f() { cout << "virtual B* f()" << endl; return new B; } }; void Func(Person& p) { p.f(); } int main() { Person ps; Student st; Func(ps); Func(st); return 0; }
- 派生类虚函数不加virtual
在重写基类虚函数时,派生类的虚函数在不加virtual关键字也可以构成重写
- 原因:
继承后基类的虚函数被继承下来了在派生类依旧保持虚函数属性)
- 示例:
class Person { public: virtual void BuyTicket() { cout << "买票-全价" << endl; } }; class Student : public Person { public: //派生类虚函数不加virtual也构成虚函数 void BuyTicket() { cout << "买票-半价" << endl; } }; void Func(Person& p) { p.BuyTicket(); } int main() { Person ps; Student st; Func(ps); Func(st); return 0; }
注意:
该种写法不是很规范,不建议这样使用
如果基类的虚函数不加virtual,派生类的虚函数加virtual,这种情况是不构成虚函数的
析构函数的重写
我们知道,基类指针和引用可以指向基类和派生对象,由此通过指针和引用释放对象时需要实现析构的多态,但基类与派生类析构函数名字不同
为了解决,编译器对析构函数的名称做了特殊处理,编译后析构函数的名称统一处理成destructor
示例:
class Person { public: virtual ~Person() { cout << "~Person()" << endl; } }; class Student : public Person { public: virtual ~Student() { cout << "~Student()" << endl; } }; //只有派生类Student的析构函数重写了Person的析构函数 //当delete对象调用析构函数,才能构成多态,才能保证p1和p2指向的对象正确的调用析构函数 int main() { Person* p1 = new Person; Person* p2 = new Student; delete p1; delete p2; return 0; }