final修饰类禁止继承,是编译期硬性约束;修饰虚函数则禁止重写但允许继承;仅作用于显式继承语法,非虚函数或非虚基类加final无效,且不可与virtual共用于类声明。

final 修饰类:禁止继承的最简写法
直接在类定义末尾加 final,编译器立刻拒绝任何 class Derived : public Base 的尝试。这不是运行时检查,是编译期硬性约束,没商量余地。
常见错误现象:error: cannot derive from 'final' base class 'Base' —— 出现这个错,说明你试图继承一个带 final 的类,而不是忘了加 final。
-
class Base final { /* ... */ };是合法写法;class Base { ... } final;是语法错误 - 不能和
virtual同时用于类(virtual class X final不合法) - 继承链中只要任意父类是
final,整个向下继承就断了,子类再加final也没意义
final 修饰虚函数:封住重写,但不封住继承
想让某个虚函数“可继承、不可覆盖”,就给它加 final。这和类级 final 完全不同作用域,常被混淆。
使用场景:基类提供标准实现(比如协议校验逻辑),明确不许子类改动,但允许子类扩展其他行为。
立即学习“C++免费学习笔记(深入)”;
-
virtual void process() final;表示该函数在当前类中是最终版,子类声明同签名函数会报错:error: virtual function 'process' cannot be overridden because it is final - 注意:
final只能修饰虚函数,对非虚成员函数加final是语法错误 - 如果父类函数是
virtual void f();,子类写void f() final;合法;但如果父类没声明virtual,子类也不能靠加final把它变成虚函数
别把 final 和 private 继承、delete 构造函数搞混
有人想“禁止继承”,却去删掉公有构造函数或用 private 继承,这是绕远路,且效果不对。
final 是唯一标准、无副作用、零成本的禁止继承机制。其他方式要么治标不治本,要么引入新问题:
-
private或protected构造函数:子类无法调用父类构造,但若父类有公有friend或静态工厂,仍可能绕过 -
= delete拷贝/移动构造函数:只影响对象创建方式,完全不限制继承 - 模板 SFINAE 或
static_assert检查std::is_base_of:只能在实例化时触发,无法阻止声明继承语句本身
final 在头文件里生效,但要注意 ODR 和模板实例化
final 是类定义的一部分,必须出现在所有翻译单元看到的定义中。如果头文件里类没写 final,而某个 CPP 文件里又重新定义了一次加了 final,就是 ODR 违规,行为未定义。
模板类加 final 要特别小心:比如 template<typename t> class Holder final { ... };</typename>,那 Holder<int></int> 和 Holder<double></double> 都不可继承,但这是各自独立的类,不是“泛型禁止”。
- 导出到动态库的
final类,其 ABI 是稳定的,但调用方若尝试继承,链接前就卡在编译阶段 - 宏展开后生成类定义时,确保
final词法上紧贴class名后或};前,空格和换行不影响,但宏参数拼接错误会导致丢失final
最容易被忽略的是:final 只作用于显式写出的继承关系,对模板偏特化、CRTP 基类、甚至某些元编程模拟的“伪继承”完全无效——它管的是 C++ 语言层面的 : 语法,不是设计意图。










