override关键字必须显式写在派生类函数声明末尾,用于强制编译器检查是否真正重写了基类虚函数;缺失时可能导致静默隐藏而非重写,引发多态失效。

override 关键字必须显式写在派生类函数声明末尾
不加 override,编译器不会检查该函数是否真的重写了基类虚函数。哪怕函数名拼错、参数类型不匹配、const 修饰不一致,只要签名“看起来像”,就会被当作新函数(隐藏而非重写),导致多态失效。
加上 override 后,编译器会严格比对:基类中是否存在可访问的、同名、同参数、同 const/volatile 限定、同返回类型的虚函数。任一不满足,立即报错。
实操建议:
- 所有你**主观意图是重写虚函数**的地方,必须写
override—— 这不是可选项,是安全底线 - 不要依赖 IDE 自动补全或“看着差不多就得了”,比如
void foo(int)和void foo(long)在 64 位 Linux 下可能等价,但编译器不认为它们是同一签名,override会直接拒掉 - 返回类型协变(如基类返回
Base*,派生类返回Derived*)是允许的,但前提是基类函数声明为虚函数且返回指针/引用;否则override仍会失败
const / noexcept / ref-qualifier 不匹配会导致 override 失败
虚函数重写的签名一致性要求比很多人想的更严格:除了参数类型和数量,const 限定、noexcept 规约、左值/右值引用限定符(& / &&)都必须完全一致,否则 override 编译失败。
立即学习“C++免费学习笔记(深入)”;
常见错误现象:
- 基类函数是
virtual void draw() const;,派生类写成void draw() override;→ 缺少const,报错 - 基类声明
virtual int get() noexcept;,派生类写int get() override;→ 隐式非noexcept,不匹配 - C++11 起支持 ref-qualifier:
void process() &和void process() &&是两个不同函数;若基类用&限定,派生类漏掉,override不通过
实操建议:复制基类函数声明,仅修改函数体,再补 override——比手敲更可靠。
override 只能用于成员函数,且基类对应函数必须是 virtual
override 不是修饰符,而是说明符(specifier),它本身不改变函数行为,只触发编译期校验。因此它有明确使用边界:
- 不能用于全局函数、静态成员函数、友元函数
- 不能用于基类中未声明为
virtual的函数(即使有同名函数)——此时写override会报 “no function to override” - 基类函数是
final的,派生类再用override也会失败(因为不可重写) - 模板类中的虚函数也可以用
override,但要注意实例化时机:只有在模板被实际具现化、且基类版本已可见时,校验才发生
示例错误:
struct Base {
void f(); // 非虚
};
struct Derived : Base {
void f() override; // 错误:Base::f 不是虚函数
};没有 override 时的典型多态失效场景
最危险的情况不是编译失败,而是**静默成功却逻辑错误**。例如:
基类定义了 virtual std::string name() const;,派生类本意重写,却误写为:
std::string name() { /* 忘了 const */ }结果:
- 没有
override→ 编译通过 - 该函数不是虚函数重写,而是新函数(隐藏)
- 通过基类指针调用
name(),仍执行基类版本,而非你写的逻辑 - 运行时表现异常,调试困难
加 override 后,上述代码立刻报错:error: 'name' marked 'override' but does not override any member functions。
真正复杂的是涉及继承链多层、模板偏特化、SFINAE 干扰的场景——这时 override 的强制校验反而成了最轻量、最可靠的防护网。别省那几个字符。










