override关键字用于显式声明虚函数重写,要求签名完全匹配或满足协变规则,是C++11引入的编译期契约,可防止因拼写、const、参数类型等不一致导致的隐式重载而非重写问题。

override 关键字用来显式声明虚函数重写
它告诉编译器:“这个函数意在重写基类的虚函数”,一旦签名不匹配(比如参数类型不同、const 修饰不一致、返回类型协变违规),编译器立刻报错,而不是静默地生成一个新函数。这是 C++11 引入的强制检查机制,本质是编译期契约。
常见错误现象包括:基类函数是 void func(int),派生类写成 void func(double) 或 void func(int) const —— 没加 override 时,编译通过但实际没重写;加上后直接报错,如:error: 'func' marked 'override' but does not override any member functions。
- 必须与基类虚函数的签名(参数类型、cv 限定符、ref-qualifier)完全一致,或满足协变返回类型规则
- 只能用于类内非静态成员函数声明,不能用于定义(即只出现在头文件类体中,不放在 .cpp 的函数实现里)
- 若基类函数未声明为
virtual,即使签名一致,也不能用override
不加 override 可能导致的隐蔽问题
没有 override 时,C++ 编译器不会校验重写意图。典型陷阱是拼写错误或参数微调:比如基类有 virtual void draw() const,派生类写了 void draw()(漏了 const),结果变成重载而非重写——多态调用时仍执行基类版本,逻辑出错却无任何警告。
这种 bug 很难调试,尤其在大型继承体系中。加 override 后,上述情况会触发编译失败,把问题拦截在早期。
立即学习“C++免费学习笔记(深入)”;
- 函数名大小写错误(
Drawvsdraw) - 参数默认值不同不影响重写判断,但加
override不会报错(默认值不是签名一部分) - 返回类型若非协变(如基类返回
Base*,派生类返回Derived*是合法协变;返回int就非法),加override会报错
override 和 virtual 能否共存?
可以,而且推荐共存。派生类中用 virtual + override 是合法且清晰的写法,例如:virtual void foo() override。这既表明该函数可被进一步派生类重写,也确认它确实在重写基类虚函数。
注意:override 本身已隐含“虚”的语义,所以仅写 void foo() override 也足够;但加 virtual 更利于代码可读性,尤其当该函数未来可能成为某更深派生类的基类虚函数时。
-
final和override也可共用:void bar() override final,表示重写且禁止再被重写 - 不能同时用
override和default或delete(它们是函数定义特性,而override是声明特性) - 纯虚函数重写也需
override,例如:void pure_func() override = 0
编译器兼容性与项目启用建议
override 是 C++11 标准特性,GCC 4.7+、Clang 3.3+、MSVC 2015+ 均完整支持。老编译器(如 GCC 4.6)会报错,此时需升级或改用宏兼容(不推荐)。
工程实践中,应将 -Woverloaded-virtual(GCC/Clang)和 /we4263 /we4264(MSVC)等警告开启,并强制使用 override。现代 C++ 代码库(如 Chromium、LLVM)已将其视为编码规范的一部分。
- CI 流程中可加入检查:grep -r "virtual.*{" | grep -v override,定位遗漏点
- 不要依赖 IDE 自动补全的
override,需人工核对基类函数签名是否真被覆盖 - 模板类中的虚函数重写同样适用
override,但要注意实例化时机和 SFINAE 影响
& / &&)的一致性——它们属于函数类型签名,差一点就不是重写。写完务必对照基类声明逐字符核对。










