必须用override,否则编译器不报错但多态静默失效;加override后签名不匹配(如参数、const、引用限定符等)会立即编译报错,将多态错误拦截在编译期。

必须用 override,否则编译器不会报错,但多态行为已失效。
基类虚函数签名变更后,派生类不加 override 就完全静默失效
比如基类把 void process() 改成 void process(int),而派生类仍保留旧版实现:void process()。此时它不再重写基类函数,而是变成一个独立的、与基类同名的普通函数(即“隐藏”而非“重写”)。通过基类指针调用时,只会执行基类版本,派生类逻辑彻底被跳过——而且编译、链接、运行全无提示。
这种错误在重构中高频出现,尤其当基类由其他团队维护或来自 SDK 时。没有 override,你就等于主动放弃编译期检查。
- 不加
override:编译器当作普通函数处理,不检查是否真有基类虚函数可重写 - 加了
override:编译器立刻报错,例如error: 'process' marked 'override' but does not override any base class members - 即使基类是模板类或带 SFINAE 的接口,只要虚函数声明存在,
override同样生效
override 要求函数签名严格匹配,连 & 和 const 都不能漏
很多重构失败不是因为参数改了,而是忽略了 C++11 起引入的引用限定符和 const/volatile 限定。比如基类定义了 virtual void draw() const &,派生类写成 void draw() const override(缺 &)或 void draw() & override(缺 const),都会触发编译错误。
这不是过度严格,而是防止你无意中写出两个不同重载版本,导致调用歧义或意外绑定到基类实现。
- 必须一致的项:
参数类型及数量、返回类型(协变允许)、const/volatile、&或&&引用限定符 - 允许差异:顶层
const(如intvsconst int)不影响匹配 - 返回类型协变只适用于指针/引用,且派生类返回类型必须是基类返回类型的派生类
批量检查所有派生类是否同步更新,靠 IDE 或静态分析工具不现实
大型项目里,一个基类可能有几十个派生类分散在不同模块。指望 IDE 的“查找所有重写”功能全覆盖?实际中常漏掉模板特化类、匿名命名空间内的类、或跨仓库的子类。更可靠的做法是:在 CI 流程中强制开启 -Woverloaded-virtual 和 -Wsuggest-override(GCC/Clang),再配合 override 全量补全。
-
-Wsuggest-override会提示哪些函数“建议加override”,但只是警告,不中断构建 - 真正起作用的是你手动补全后触发的编译失败——这才是唯一可信的兼容性验证
- 如果某些派生类暂时无法修改(如第三方库封装层),可用
[[maybe_unused]]或注释说明原因,但不要删掉override来“绕过”检查
纯虚函数新增后,派生类未实现会导致链接失败,但时机比 override 检查更晚
基类新增一个纯虚函数 virtual void serialize() = 0,所有直接/间接派生类若未提供定义,将无法实例化——但这个错误发生在链接阶段,而不是编译阶段。你可能先看到 undefined reference to 'VTT for Derived' 或类似虚表相关错误,排查路径更长。
相比之下,override 是编译期拦截,位置精准、信息明确。所以对已有虚函数的签名调整,优先依赖 override;对新增纯虚函数,则需配合单元测试中的构造实例断言(例如 static_assert(std::is_constructible_v<derived>)</derived>)来兜底。
最易被忽略的一点:基类虚函数加了 final,派生类再用 override 就会报错——这本身也是兼容性破坏,但容易被当成“语法错误”忽略其设计意图。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











