结论:禁止继承用final,禁止实例化用抽象类或=delete;final不干扰抽象性,抽象类本身已不可实例化,无需额外删构造函数。

直接说结论:禁止继承用 final,禁止实例化用抽象类或 = delete 构造函数;两者混用时,final 不影响抽象性,但抽象类本身已隐含“不可实例化”,无需额外删构造函数。
用 final 关键字阻止继承(C++11 起)
这是最干净、无副作用的方式,编译器在派生时直接报错,不引入虚基类、友元或模板等间接机制。
- 写法就是
class MyClass final : public Base {};,之后任何class Derived : public MyClass {};都会触发错误:error: cannot derive from 'final' class 'MyClass' -
final只作用于继承关系,不影响该类自身能否被实例化——如果它有公有构造函数,仍可MyClass obj; - 不能和
virtual修饰符共存于同一函数声明中;也不能用于类模板参数,但可用于特化后的类名(如template class MyTemplate<int> final;</int>不合法,但using IntFinal = MyTemplate<int> final;</int>合法) - 注意:
final是语法级限制,无法被友元、模板或反射绕过,比老式私有构造+虚继承方案更可靠
让类无法被实例化:抽象类 vs = delete
二者语义不同,选错会导致设计失焦。
- 用纯虚函数制造抽象类(如
virtual void dummy() = 0;或virtual ~MyClass() = 0;):适合定义接口、强制子类实现行为。但会引入虚表,哪怕只有一处虚函数;析构函数为纯虚时,必须在类外提供定义(哪怕空实现),否则链接失败 - 用
= delete封禁所有构造路径:更适合工具类(全静态成员)。必须显式删除全部可能入口:MyClass() = delete;、MyClass(const MyClass&) = delete;、MyClass(MyClass&&) = delete;、void* operator new(std::size_t) = delete;、void operator delete(void*) = delete; - 只删默认构造函数(
MyClass() = delete;)不够:用户仍可用new MyClass{}或拷贝构造触发隐式调用 - 若类只有 static 成员,强烈建议改用
namespace——没有构造/析构开销,无访问控制复杂度,也天然不可实例化
禁止继承 + 禁止实例化:组合使用要注意什么
这不是简单叠加,而是要厘清意图。比如你写了一个不可继承的工具类,又想防误用——这时抽象类反而画蛇添足。
立即学习“C++免费学习笔记(深入)”;
- 若目标是“这个类只供静态调用,且谁都不许继承它”,就用
final+ 全部构造函数= delete。不要加纯虚函数,否则徒增虚表和继承暗示 - 若目标是“这是一个接口基类,必须被继承,但绝不允许直接 new 或栈上构造”,那就用抽象类 +
protected构造函数(而非private),再加final就矛盾了——抽象类本意就是被继承的 - 友元和模板仍是破口:即使你
= delete所有构造函数,只要类声明了friend class Helper;,Helper仍能构造它;同理,模板中若出现T{}且T是你的禁实例化类,错误发生在模板实例化点,堆栈深、定位难
最容易被忽略的点是:禁止实例化 ≠ 禁止对象存在。静态局部变量(Magic Static)、静态成员对象、或友元类内部创建的对象,都可能绕过表面限制。真正要堵死,得从构造入口、内存分配、以及所有潜在调用上下文三方面同时封禁。


















