final类是编译期强制禁止继承的机制,类名后加final即标记为不可派生,声明继承时立即报错,不依赖访问控制、友元或运行时检查,语义明确且零开销。

final 类在编译期被标记为“继承禁区”
因为 final 是 C++11 引入的**编译期强制约束机制**,不是运行时检查,也不是访问控制技巧。当你写 class A final { },编译器会将该类的类型信息打上不可派生标签;一旦在后续代码中出现 class B : public A { },编译器立刻报错(如 error: cannot derive from 'final' base class 'A'),根本不会进入语义分析或代码生成阶段。
它和 private 构造函数有本质区别
常见误解是“只要构造函数私有,子类就调不了,所以不能继承”。但这是错的:
- 私有构造函数 + 友元类 → 子类可合法继承(只要友元权限放行)
- 私有构造函数 + 模板特化 / 成员函数内 new → 仍可能绕过
-
final不依赖访问控制,不关心友元、不看作用域,只认语法位置:类名后带final就是铁律 - 错误写法如
class final A { }或class A { ... } final;都无效 ——final必须紧贴类名,且仅出现在类头定义末尾
为什么虚继承 + 私有基类方案不等于 final
那种用 template<typename t> class MakeFinal { friend T; private: MakeFinal(); }</typename> + 虚继承的旧方案,本质是“制造构造失败”,而非禁止继承本身:
- 它依赖虚基类初始化规则:派生类必须直接构造虚基类,而私有构造拦住这一步
- 但它无法阻止声明继承(
class B : public FinalClass2 { };本身能编译通过)—— 错误只在实例化B b;时才暴露 - 它引入虚基类指针开销,破坏 ABI 稳定性,且对模板推导、
std::is_base_of等元编程行为不友好 -
final则从声明那一刻起就切断所有继承路径,连声明都通不过,语义干净、无歧义、零运行时代价
final 类仍可被正常使用
被标记 final 的类不是“废类”,它只是关闭了继承通道:
- 可以正常实例化(栈/堆均可):
A a;、auto p = std::make_unique<a>();</a> - 可以作为成员、参数、返回值、模板实参,完全不影响使用场景
- 可以继承其他类(
class A final : public Base { }合法) - 其虚函数仍可被调用,也可被标记
final单独限制重写
真正容易忽略的是:final 的约束粒度极细,它不阻止你用组合替代继承,也不影响多态接口设计 —— 它只回答一个问题:“这个类,是否允许别人改写它的类型关系?”答“否”,就加 final,别犹豫。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











