纯虚函数是使类成为抽象类、禁止其实例化的最直观方式,需声明至少一个如virtual void f() = 0;的纯虚函数;若析构函数为纯虚,须在类外提供定义。

直接禁止类被实例化,只有两种编译期有效手段:让类变成抽象类,或显式 = delete 所有构造路径。靠“不写构造函数”“只写私有构造”都不保险——编译器会自动生成、友元能绕过、静态成员仍可触发实例化。
用纯虚函数制造抽象类
最直观、语义最明确的方式:在类中声明至少一个纯虚函数,例如 virtual void dummy() = 0; 或 virtual ~MyClass() = 0;。
这样写之后,MyClass obj;、new MyClass、MyClass{}; 全部编译失败,错误信息清晰:error: cannot declare variable of abstract type 'MyClass'。
- 适合需要被继承、强制子类实现接口的场景(如
Shape、Logger) - 若析构函数设为纯虚,必须在类外提供定义(哪怕空实现),否则链接失败:
MyClass::~MyClass() {} - 虚表开销存在,纯工具类(仅含
static成员)不该走这条路
用 = delete 封死所有构造方式
对工具类更干净:显式删除默认构造、拷贝、移动、以及堆分配入口。
立即学习“C++免费学习笔记(深入)”;
典型写法:
class Utils {
public:
Utils() = delete;
Utils(const Utils&) = delete;
Utils(Utils&&) = delete;
Utils& operator=(const Utils&) = delete;
Utils& operator=(Utils&&) = delete;
void* operator new(std::size_t) = delete;
void operator delete(void*) = delete;
// 可选:禁掉数组形式
void* operator new[](std::size_t) = delete;
void operator delete[](void*) = delete;
};
- 仅删构造函数不够——
new Utils仍可能成功,必须连operator new一起删 - 不写移动函数时,C++11 起编译器可能隐式生成,所以显式
= delete更安全 - 如果类真只是放静态函数,直接用
namespace替代,彻底避开类实例化问题
私有构造函数为什么不可靠
只把构造函数设为 private 看似封住了外部调用,但实际漏洞很多:
- 类内静态成员变量(如
static Utils instance;)仍会触发构造 - 任何
friend函数或类都能无视private,直接调用构造函数 - 模板代码中出现
T{},而T是你的类,会在实例化点报错——但错误位置远离原始调用处,排查困难 -
protected构造更危险:派生类可继承并公开构造,客户代码借道派生类完成实例化
最容易被忽略的破口:友元与模板实例化
你以为删光了构造函数就高枕无忧?不一定。
只要类里写了 friend class Helper;,Helper 就能自由调用已被 = delete 的构造函数——访问控制和删除说明符是两套机制,友元同时 bypass 二者。
模板也一样:如果某个泛型算法写了 Container<t> c{T{}};</t>,而你把 T 实例化为禁实例化类,编译器会在该模板实例化的位置报错,而不是在类定义处。错误栈可能跨多个头文件,定位成本很高。
真正想杜绝一切实例化,要么用抽象类(语义强、限制稳),要么接受 namespace 的简洁性——别硬套类壳子。


















