override用于显式声明覆盖虚函数,防止签名不匹配导致的静默新函数;final用于禁止继承或重写,二者均为编译期检查,零运行时开销。
override 用来告诉编译器“我明确想覆盖基类虚函数”
不加
时,哪怕函数签名稍有不同(比如参数类型不一致、const 修饰不匹配、返回类型协变没写对),编译器也不会报错,而是静默地声明了一个**新函数**,而不是覆盖。这会导致运行时调用不到预期的派生类版本,bug 难以发现。
加上
后,编译器会严格比对:该函数是否确实存在于某个可访问的基类中、是否为虚函数、签名是否完全匹配(含 const/volatile/ref-qualifier)。不满足任一条件就直接报错。
常见错误现象:
在基类中是
,子类写
→ 编译失败
使用场景:所有你本意是覆盖虚函数的地方,都应加
,尤其是重构后或多人协作时
性能影响:零开销,纯编译期检查
final 用于禁止进一步继承或覆盖
可作用于两个位置:类定义后(禁止被继承)、虚函数声明后(禁止被重写)。它不是运行时控制,而是编译期强制约束。
类上加
:
→ 其他类再继承
会触发
编译错误
:
函数上加
:
→ 派生类中再写
会报错:
注意:不能同时用
和
修饰同一个函数——语法允许,但语义上合理(覆盖并封顶),例如:
不写 override 的真实风险:签名漂移无人察觉
下面这段代码在没有
时能编译通过,但行为不符合直觉:
立即学习
“
C++免费学习笔记(深入)
”;
C函数速查手册(CHM版)
C函数速查手册(CHM版)
下载
加了
后,
那一行立刻报错,问题暴露得早且明确。
容易踩的坑:用 IDE 自动生成重写函数时,有些老版本插件不自动补
兼容性:C++11 起支持,所有现代编译器(GCC 4.7+、Clang 3.2+、MSVC 2012+)都完整支持
override 和 final 不解决运行时多态逻辑错误
它们只管“有没有覆盖”和“能不能覆盖”,不管覆盖后的函数逻辑是否正确。比如:
子类
了
,但内部返回了
而非
→ 编译通过,运行时出错
把
加在关键算法函数上防止误改,但若该函数本身有逻辑缺陷,
反而让修复更麻烦(需改设计)
真正容易被忽略的是:这两个关键字必须配合虚函数机制起作用;非虚函数加
是语法错误,加
则无意义。
overrideoverridevoid func(int)virtual void func(double)void func(int) overrideoverridefinalfinalclass Widget final : public Base { ... };Widgeterror: cannot derive from 'final' classfinalvirtual void draw() final;void draw() overrideerror: virtual function 'draw' cannot be overriddenoverridefinalvoid draw() override final;override
struct Base {
virtual void log(const std::string& msg) {}
};
struct Derived : Base {
void log(std::string msg) { /* 注意:少了 const& */ }
};
Base* p = new Derived();
p->log("hello"); // 调用的是 Base::log,不是 Derived::log!
overrideDerived::logoverrideoverrideclone()new Basenew Derivedfinalfinaloverridefinal