final必须紧邻类定义右花括号后、分号前才生效,位置错误则被忽略;类级final阻止继承,函数级final(需virtual)阻止重写;不加final易致析构不全、浅拷贝等隐患,应默认使用。

为什么加了 final 还能被继承?
常见现象是:明明在类名后写了 final,编译器却没报错,子类照样能定义成功。根本原因是——final 必须紧跟在类定义的 右花括号之后、分号之前,位置错一点就失效。
错误写法:
class Base final { // ✅ 正确:final 在类头
// ...
};但若写成class Base {
// ...
} final; // ❌ 错误:final 放在类体外,完全无效此时 final 被解析为标识符或语法错误(取决于上下文),编译器直接忽略。
-
final是 C++11 引入的说明符,不是关键字(不能单独用),只能修饰类定义或虚函数声明 - 必须与
class/struct定义在同一声明语句中,且紧邻右花括号 - VS2013+、GCC 4.7+、Clang 3.1+ 支持;老编译器会报错或静默忽略
final 和 virtual 一起用时要注意什么?
类本身加 final,不影响其内部是否含 virtual 函数;但若想禁止某个虚函数被重写,得把 final 加在函数声明末尾,而不是类上。
例如:
class Base {
public:
virtual void func() final {} // ✅ 禁止子类重写 func()
};
class Derived : public Base {
public:
void func() override {} // ❌ 编译错误:cannot override final function
};
- 类级
final阻止继承,函数级final阻止重写,二者不冲突,可共存 - 函数加
final前必须有virtual(否则无意义,编译器可能警告) - 如果父类函数已标记
final,子类再用override就会触发编译错误,不是运行时行为
不加 final 的隐式风险有哪些?
没显式禁止继承,不代表安全。尤其当类有非虚析构函数、或内部持有裸指针/资源但没实现移动语义时,被意外继承可能导致:
- 通过基类指针 delete 派生对象 → 析构不完整(未调用派生类析构函数)
- 派生类新增成员变量,但基类拷贝/移动构造函数未适配 → 浅拷贝、资源重复释放
- 多态调用时,因虚函数表布局变化引发 ABI 不兼容(尤其跨 DLL/so 场景)
所以,**只要你不设计成基类,就该默认加 final**。这不是防御性编程,而是明确意图:这个类就是终态。
立即学习“C++免费学习笔记(深入)”;
替代方案:私有析构 + 友元?别这么干
有人用私有析构函数 + 友元类绕过 final,或者靠文档“约定”不继承。这些做法实际效果差:
- 私有析构会让所有使用者无法栈上创建对象,也拦不住继承(派生类可声明公有析构)
- 友元破坏封装,且无法阻止第三方继承
- 注释和文档在编译期零约束力,CI 或新成员很容易踩坑
final 是唯一编译期强制、零运行时代价、语义清晰的机制。它不改变接口,只收紧契约——这点恰恰容易被忽略:你加 final 不是为了“锁死”,而是让错误在写错第一行继承代码时就暴露出来。











