加final是唯一编译器强制、零歧义、无运行时代价的禁止继承方案,必须紧贴类名后、花括号前书写,如class widget final { };,其他写法无效或报错。

直接加 final,别绕弯——这是唯一编译器强制、零歧义、无运行时代价的方案。
class 名后紧贴写 final 才生效
语法位置极其严格:final 必须紧跟在类名之后、花括号之前,且不能换行或加空格隔开。任何其他写法都会被忽略或报错。
-
class Widget final { };✅ 正确 -
class final Widget { };❌ 编译器当普通标识符处理,不报错但无效 -
class Widget { } final;❌ 语法错误,final不是语句后缀 -
class Widget final : public Base { };✅ 合法,final和继承列表不冲突
继承时立即报错,不是实例化时才拦
错误发生在声明派生类那一刻,不是等到构造对象。这和私有构造函数有本质区别:后者允许写 class B : public A { };,只在 B b; 或 new B 时失败。
- 写
class Derived : public MathUtils final { };→ 编译器立刻报error: cannot derive from 'final' base class 'MathUtils' - 不会生成任何目标码,不引入虚基类指针、不破坏 ABI、不影响
std::is_base_of等元编程结果 - 友元类、模板特化、
reinterpret_cast全部无效——final是语法层封禁,不是访问控制层设障
不是所有“看起来像禁止”的做法都可靠
靠 private 构造函数、protected 析构、空虚函数或 static_assert 检测,都属于“软限制”,容易被绕过或延迟暴露问题。
-
private构造函数 + 友元类 → 继承合法,Derived d;仍能编译通过 -
protected virtual ~Base() = default;→ 只阻止栈上实例化,不影响继承声明 - 用模板
static_assert(!std::is_base_of_v<base t>)→ 只在模板实例化时检查,对普通继承无效 - 这些方式还可能干扰内联优化、增加二进制体积、让 IDE 代码跳转失效
真正该加 final 的地方,往往是你写完类就该决定的:这个类是否允许别人改写它的类型关系?答案是否,就加。别等出 bug 再补,也别指望靠注释或文档约束他人。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











