一、上期回顾
继承语法、三种继承权限、父子构造析构顺序、子类调用父类构造、同名隐藏。封装、继承学完,今天拿下多态,OOP 三大特性彻底收官。
二、什么是多态
一句话:一个接口,多种实现。
- 父类引用 / 指针,指向子类对象
- 调用同一个函数,执行子类自己的版本
价值:
- 程序扩展性极强
- 符合开闭原则:新增子类不用改原有代码
- 框架、驱动、嵌入式业务层大量用到
三、多态实现条件(面试必背三条)
- 必须有继承关系
- 父类中有虚函数 virtual
- 用父类指针 / 父类引用指向子类对象
满足三条,触发动态绑定,实现多态。
四、虚函数与普通函数区别
普通成员函数
静态绑定:编译阶段就确定调用哪个类的函数,看指针类型。
虚函数 virtual
动态绑定:运行时看对象真实类型,调用子类重写版本。
五、多态完整示例代码
#include <iostream> using namespace std; // 父类 class Animal { public: // 虚函数 virtual void speak() { cout << "动物发出声音" << endl; } }; // 子类Dog class Dog : public Animal { public: // 重写虚函数 void speak() { cout << "小狗汪汪叫" << endl; } }; // 子类Cat class Cat : public Animal { public: void speak() { cout << "小猫喵喵叫" << endl; } }; int main() { Animal* p; p = new Dog(); p->speak(); // 执行Dog版本 p = new Cat(); p->speak(); // 执行Cat版本 return 0; }运行结果:
plaintext
小狗汪汪叫 小猫喵喵叫六、重写(覆盖)规则
子类重写父类虚函数要求:
- 函数名、参数列表、返回值完全一致
- 不加 virtual 也可以,继承自带虚属性
- C++11 推荐加
override显式标识,防止写错:
void speak() override { cout << "小猫喵喵叫" << endl; }七、虚析构函数(大坑必考)
当父类指针 delete 子类对象时:
- 若析构不是虚函数,只调用父类析构,子类析构不执行→ 内存泄漏
正确写法:父类析构加 virtual
class Animal { public: virtual ~Animal() { cout << "父类析构" << endl; } };口诀:有继承多态,析构必写虚。
八、纯虚函数 & 抽象类
纯虚函数格式
virtual void func() = 0;抽象类特点
- 包含纯虚函数的类叫抽象类
- 不能实例化对象
- 只能被继承,子类必须全部重写纯虚函数才能实例化
- 用来做接口规范
示例:
class Shape { public: // 纯虚函数 virtual void getArea() = 0; }; // 必须重写才能创建对象 class Circle : public Shape { public: void getArea() override { cout << "圆形面积计算" << endl; } };九、今日核心总结
- 多态三要素:继承 + 虚函数 + 父类指针 / 引用
- 虚函数实现动态绑定,普通函数静态绑定
- 多态:一个接口,多种实现,扩展性拉满
- 多态场景下,析构函数必须加 virtual
- 纯虚函数构成抽象类,只能做基类、定接口规范
十、课后练习
- 写父类 Shape 抽象类,纯虚函数 getArea ()
- 写 Rectangle、Circle 子类重写求面积
- 用父类指针指向不同子类,感受多态效果