多态需基类函数声明virtual且通过基类指针或引用调用;子类重写须加override确保匹配;纯虚函数可有定义,派生类仍可显式调用。

多态在 C++ 里不是靠“写个接口”自动生效的,而是靠 virtual 关键字显式开启、靠指针/引用调用才触发——不满足这两条,哪怕函数签名一模一样,也只会静态绑定。
为什么基类函数加了 virtual,子类重写后还是不走多态?
最常见原因是:没通过基类指针或引用调用。直接用子类对象调用(obj.func()),编译器在编译期就确定了函数地址,根本不会查虚表。
- ✅ 正确:用
Base* ptr = new Derived(); ptr->func();或Base& ref = derived_obj; ref.func(); - ❌ 错误:直接
Derived d; d.func();—— 这是普通函数调用,跟虚函数无关 - ⚠️ 注意:返回值类型不能仅靠协变触发多态,必须函数名、参数列表、
const修饰完全一致(否则是重载,不是重写)
override 不是可选语法糖,它是编译期防错刚需
不加 override,子类函数可能因拼写错误、参数类型微差(比如 int vs const int&)、const 缺失等原因,意外变成新函数而非重写,导致多态失效且毫无提示。
- ✅ 强制加
override:编译器会校验是否真能重写基类virtual函数,不匹配直接报错 - ❌ 不加时典型坑:
void func(int)在基类,子类写成void func(int*)—— 看似像重写,实为重载,多态完全不生效 - ?
override和virtual可共存(子类中),但virtual非必需;而基类函数必须有virtual,否则override会编译失败
纯虚函数 = 0 的本质是“强制派生类实现”,不是“禁止基类定义”
virtual void func() = 0; 只表示该函数无默认实现,但你依然可以在基类里提供定义(只要不省略函数体),派生类仍可用 Base::func() 显式调用。
立即学习“C++免费学习笔记(深入)”;
- ✅ 合法写法:
virtual void func() = 0 { std::cout (C++11 起允许) - ❌ 常见误解:认为纯虚函数就不能有函数体 —— 实际上可以有,只是它不能让类变成非抽象类
- ⚠️ 抽象类不能实例化,但可以有构造函数、成员变量、非纯虚函数;派生类只要没实现全部纯虚函数,它仍是抽象类
虚函数调用的开销很小但真实存在:每次调用要查虚表(一次指针解引用 + 偏移计算),而内联、模板、函数对象都绕不开这个间接层。如果某个类确定不会被继承(或继承关系极浅),别为了“设计感”盲目加 virtual——多态不是免费的,它的代价藏在间接跳转里。










