一、上期回顾 

继承语法、三种继承权限、父子构造析构顺序、子类调用父类构造、同名隐藏。封装、继承学完,今天拿下多态,OOP 三大特性彻底收官。


二、什么是多态

一句话:一个接口,多种实现

  • 父类引用 / 指针,指向子类对象
  • 调用同一个函数,执行子类自己的版本

价值:

  1. 程序扩展性极强
  2. 符合开闭原则:新增子类不用改原有代码
  3. 框架、驱动、嵌入式业务层大量用到

三、多态实现条件(面试必背三条)

  1. 必须有继承关系
  2. 父类中有虚函数 virtual
  3. 父类指针 / 父类引用 指向子类对象

满足三条,触发动态绑定,实现多态。


四、虚函数与普通函数区别

普通成员函数

静态绑定:编译阶段就确定调用哪个类的函数,看指针类型。

虚函数 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;

抽象类特点

  1. 包含纯虚函数的类叫抽象类
  2. 不能实例化对象
  3. 只能被继承,子类必须全部重写纯虚函数才能实例化
  4. 用来做接口规范

示例:

class Shape
{
public:
    // 纯虚函数
    virtual void getArea() = 0;
};

// 必须重写才能创建对象
class Circle : public Shape
{
public:
    void getArea() override
    {
        cout << "圆形面积计算" << endl;
    }
};

九、今日核心总结

  1. 多态三要素:继承 + 虚函数 + 父类指针 / 引用
  2. 虚函数实现动态绑定,普通函数静态绑定
  3. 多态:一个接口,多种实现,扩展性拉满
  4. 多态场景下,析构函数必须加 virtual
  5. 纯虚函数构成抽象类,只能做基类、定接口规范

十、课后练习

  1. 写父类 Shape 抽象类,纯虚函数 getArea ()
  2. 写 Rectangle、Circle 子类重写求面积
  3. 用父类指针指向不同子类,感受多态效果

更多推荐