override确保派生类函数精准重写基类虚函数,签名不匹配则编译报错;基类新增纯虚函数迫使派生类实现,否则无法实例化;非虚函数修改不触发重写,易致多态失效。

基类虚函数签名变更后,override 会直接报错
基类虚函数加参数、改返回类型、增 const 限定符,只要和派生类中带 override 的函数不匹配,编译器立刻拒绝——这是 override 最实在的价值。它把“运行时调错函数”的隐患,提前到编译期炸出来。
常见错误现象:error: 'func' marked 'override' but does not override any member functions 或 error: overriding function differs from base class only in return type
- 必须确保派生类函数签名(含参数类型、
const、引用限定符)与基类完全一致,协变返回类型除外 - 基类若从非虚函数改为虚函数,原派生类同名函数不会自动变成重写;必须显式加
override才触发检查 - 如果派生类没加
override,哪怕签名已错,编译也过——它只是普通函数,不参与多态,也不会报错
基类新增纯虚函数,未实现的派生类会编译失败
当基类加入新的纯虚函数(如 virtual void serialize() = 0;),所有非抽象的派生类必须提供实现,否则无法实例化。
常见错误现象:error: cannot declare variable 'd' to be of abstract type 'Derived'
- 抽象类不能被构造,所以只要派生类还缺一个纯虚函数实现,就仍是抽象类
- 若想临时绕过,可让派生类也声明为
abstract(即自己也加一个纯虚函数),但通常说明接口契约已变,应尽快补全 - 注意:私有继承或保护继承下,基类纯虚函数对派生类用户不可见,但派生类自身仍需实现才能脱离抽象状态
基类非虚函数被修改,派生类同名函数可能意外隐藏而非重写
基类中一个普通成员函数(无 virtual)被改成虚函数,或增加 const,而派生类里恰好有同名函数但没加 override,此时派生类函数不会变成重写,而是继续隐藏基类版本——行为不变,但语义已错。
常见错误现象:调用基类指针的该函数,执行的仍是基类实现,而非预期的派生类逻辑
- 这种“看似能跑,实际没多态”的问题最难排查,
override对非虚基函数无效,所以加了也没用 - 真正安全的做法是:只要基类函数意图支持多态,就必须声明为
virtual,且所有派生类对应函数必须显式加override - 工具辅助:Clang-Tidy 的
cert-oop54-cpp规则可检测“本该是虚函数却不是”的情况
用 dynamic_cast 验证运行时类型,但别依赖它查重写
dynamic_cast 能确认指针是否指向某具体派生类,但它不告诉你“这个虚函数有没有被重写”,只告诉你“对象是不是那个类型”。想验证重写是否生效,得靠调用+日志/断点,或静态检查工具。
-
dynamic_cast要求基类至少有一个虚函数(即多态类型),否则编译失败 - 即使
dynamic_cast成功,也不能代替对override和虚函数声明的审查——它解决的是“是什么类型”,不是“有没有重写” - 高频路径避免
dynamic_cast,它有运行时开销;设计上优先用虚函数统一接口,而不是 downcast 后分发
最易被忽略的一点:接口变更的影响,往往不在编译错误里,而在那些没加 override、没声明为虚、甚至根本没被测试覆盖的派生类函数上。它们安静地编译通过,然后在某个深夜的线上请求里,悄悄走错分支。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











