C++多态需同时满足继承关系、虚函数声明和指针/引用调用三个条件;虚函数启用动态绑定,通过vtable实现运行时决议,纯虚函数定义接口契约,抽象类不可实例化。

多态在C++中不是“自动发生”的,它依赖三个明确条件:继承关系、虚函数(virtual)、通过指针或引用调用。缺一不可。
虚函数:多态的开关
只有被声明为 virtual 的成员函数,才能在派生类中被“动态重写”。编译器据此生成虚函数表(vtable),运行时根据对象实际类型查表调用对应函数。
- 基类中必须用 virtual 声明,否则即使派生类同名函数签名一致,也属于隐藏(hiding),不是重写(override)
- C++11 起推荐在派生类中加 override 关键字,让编译器检查是否真正在重写虚函数,避免拼写错误或参数不匹配导致静默失败
- 构造函数不能是虚函数;析构函数建议声明为 virtual(尤其当基类指针可能 delete 派生类对象时),否则派生部分不会被正确析构
指针/引用:多态的载体
直接用对象调用永远走静态绑定(编译期决定),只有通过基类指针或引用,才能触发动态绑定(运行期查 vtable)。
- 正确:Base* p = new Derived(); p->func(); → 调用 Derived::func()
- 错误:Base b; Derived d; b = d; b.func(); → 发生切片(slicing),调用 Base::func()
- 引用同理:Base& r = d; r.func(); → 正确触发动态绑定
纯虚函数与抽象类:强制接口契约
声明为 virtual 返回类型 函数名() = 0; 的函数叫纯虚函数。含纯虚函数的类是抽象类,不能实例化,只能被继承。
立即学习“C++免费学习笔记(深入)”;
- 派生类必须实现所有纯虚函数,否则自身也是抽象类
- 这是实现“接口定义”和“模板方法模式”的基础,例如:Shape 类定义 virtual void draw() = 0;,Circle 和 Rect 各自实现
- 纯虚函数可以有定义(少见但合法),供派生类显式调用,如 Base::func();
静态多态?别混淆:模板不是运行时多态
函数重载、运算符重载、模板特化属于静态多态(编译期确定),和继承+虚函数构成的动态多态本质不同。它们不依赖对象类型,也不需要虚函数表。
- 模板实例化发生在编译期,每个类型生成一份代码;虚函数调用发生在运行期,共享同一份代码但跳转不同地址
- 不要把 std::vector
和 std::vector<:string> 的差异理解成多态——那是泛型,不是 OOP 多态
基本上就这些。C++ 多态不复杂,但虚函数机制、对象切片、抽象类边界这些点容易忽略或误解。抓住“virtual + 指针/引用 + 运行时决议”这个铁三角,就能稳住核心逻辑。










