C++多态编程:从原理到实战

一、多态核心概念

1. 什么是多态?

同一个行为,不同对象有不同实现 。父类引用 / 指针 指向 子类对象,调用函数时,执行子类重写的版本

2. 多态价值

  • 降低耦合,代码高扩展
  • 父类统一接口,子类自由实现
  • 新增子类无需修改原有业务代码,符合开闭原则

3. 实现多态的三大必要条件

  1. 必须存在继承关系
  2. 父类函数必须加 virtual 虚函数
  3. 父类指针 / 引用 指向 子类对象(向上转型)

二、静态绑定 & 动态绑定

  1. **静态绑定(早绑定)**编译阶段确定函数地址,普通成员函数默认都是静态绑定。
  2. 动态绑定(晚绑定) 运行阶段根据真实对象类型 匹配函数,虚函数触发动态绑定 → 产生多态。

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

向上转型 + 多态调用

复制代码
// 父类指针指向子类对象
void doSpeak(Animal *a)
{
    a->speak(); 
}

int main()
{
    Dog d;
    Cat c;

    doSpeak(&d);
    doSpeak(&c);

    return 0;
}

输出:

复制代码
小狗汪汪叫
小猫喵喵叫

同一接口 speak(),不同子类不同表现,多态生效


四、函数重写(override)规则

  1. 子类函数与父类函数名、参数、返回值完全一致

  2. 父类必须是 virtual 虚函数

  3. 子类可加 override 关键字显式标记,编译器校验

    void speak() override;

重写 / 重载 / 隐藏 三者区分

  1. 重载:同类中,同名不同参,编译绑定
  2. 隐藏:继承中,子类同名函数屏蔽父类,无 virtual
  3. 重写:继承 + 虚函数,运行绑定,实现多态

五、向上转型 & 向下转型

1. 向上转型(多态核心,常用)

子类对象 赋值给 父类指针 / 引用语法安全、自动转换,多态全部依赖它。

复制代码
Animal* a = new Dog;

2. 向下转型(不安全,少用)

父类指针强制转回子类,需要手动强转,容易越界。

复制代码
Dog* d = (Dog*)a;

六、虚析构函数(工程必踩坑)

当父类指针指向子类堆对象,delete 释放时:

  • 若析构非虚:只调用父类析构,子类资源不释放 → 内存泄漏
  • 父类加 virtual 虚析构:先子类析构,再父类析构

标准写法

复制代码
class Animal
{
public:
    virtual ~Animal(){}
};

只要类中有虚函数,必须把析构写成虚析构。


七、纯虚函数 & 抽象类

1. 纯虚函数语法

复制代码
virtual void func() = 0;

2. 抽象类

包含至少一个纯虚函数的类,特点:

  • 无法实例化对象
  • 只做父类,定义统一接口
  • 子类必须重写所有纯虚函数,否则子类也是抽象类

示例

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

// 圆形子类必须实现纯虚函数
class Circle : public Shape
{
public:
    void getArea() override
    {
        cout << "计算圆形面积" << endl;
    }
};

八、多态底层简单理解

  • 含有虚函数的类,内部会生成虚函数表 (vtable)
  • 对象自带虚表指针 (vptr)
  • 运行时通过虚表指针,找到真实子类的函数地址
  • 实现运行时动态绑定

九、高频易错点

  1. 忘了写 virtual,只会触发隐藏,没有多态
  2. 重写时参数 / 返回值不一致,不构成重写
  3. 父类指针 delete 子类对象,未写虚析构 → 内存泄漏
  4. 抽象类直接实例化对象,编译报错
  5. 混淆重载、重写、隐藏三种概念

十、今日核心总结

  1. 多态三要素:继承 + 虚函数 + 向上转型
  2. virtual 开启动态绑定,运行时决定调用哪个函数
  3. 子类重写虚函数,实现个性化逻辑
  4. 有虚函数必须搭配虚析构
  5. 纯虚函数 → 抽象类,用于定义标准接口
相关推荐
Highcharts.js5 小时前
倒置百分比堆叠面积图表示列详解|Highcharts大气成分图表代码
开发语言·信息可视化·highcharts·图表开发·面积图·图表示例·推叠图
csdn_aspnet5 小时前
C语言 Lomuto分区算法(Lomuto Partition Algorithm)
c语言·开发语言·算法
晨曦中的暮雨5 小时前
4.15腾讯 CSIG云服务产线 一面
java·开发语言
存在morning5 小时前
【GO语言开发实践】二 GO 并发快速上手
大数据·开发语言·golang
xiaoerbuyu12337 小时前
开源Java 邮箱 基于SpringBoot+Vue前后端分离的电子邮件
java·开发语言
C+++Python7 小时前
C++ 进阶学习完整指南
java·c++·学习
sparEE8 小时前
c++值类别、右值引用和移动语义
开发语言·c++
zhangjw348 小时前
第11篇:Java Map集合详解,HashMap底层原理、哈希冲突、JDK1.8优化、遍历方式彻底吃透
java·开发语言·哈希算法
jrrz08288 小时前
Apollo MPC Controller
c++·自动驾驶·apollo·mpc·横向控制·lateral control
benpaodeDD9 小时前
视频10,11,12,13——java程序的加载与执行,安装jdk
java·开发语言