可以,私有构造函数在单例和工厂模式中必须或常用,用于禁止外部直接实例化、控制对象创建权,类内静态函数或友元可调用,影响继承与移动语义。

构造函数可以是私有的吗
可以,而且在特定设计模式中必须是私有的。C++ 允许将构造函数声明为 private、protected 或 public,访问控制和其他成员函数一致。
私有构造函数的核心作用是:禁止外部代码直接调用 new 或栈上实例化,把对象创建权收归类内部或友元。这不是语法糖,而是编译期强制约束。
- 类外写
MyClass obj;或new MyClass()会触发编译错误:error: 'MyClass::MyClass()' is private - 类内静态成员函数(如
getInstance())仍可调用私有构造函数 - 友元函数或友元类也能调用私有构造函数——这是单例中允许测试框架注入的常见做法
- 继承时若基类构造函数私有,派生类无法构造,除非基类显式授予友元权限
单例模式为何依赖私有构造函数
单例的本质不是“只生成一个对象”,而是“全局唯一且可控的实例入口”。私有构造函数是实现该约束的最小必要条件。
典型实现中,getInstance() 是唯一合法出口,它内部负责判断是否已存在实例,并在首次调用时通过私有构造函数初始化:
立即学习“C++免费学习笔记(深入)”;
class Singleton {
private:
static Singleton* instance;
Singleton() = default; // 私有,禁止外部构造
public:
static Singleton* getInstance() {
if (!instance) instance = new Singleton(); // OK:类内可访问
return instance;
}
};- 不加
private,用户随时能绕过getInstance()创建新对象,单例失效 - C++11 起推荐用局部静态变量实现线程安全单例:
static Singleton& getInstance() { static Singleton inst; return inst; },仍需私有构造 - 注意:私有构造函数 + 默认构造函数 = 无法被继承(除非用
friend放开),这是有意为之的设计取舍
工厂模式里私有构造函数的用途差异
工厂模式不追求“唯一实例”,而追求“创建逻辑集中封装”。私有构造函数在这里的作用是防止误用,而非强制单例。
比如一个图形工厂返回不同形状,但所有形状都应由工厂统一创建,避免用户自行构造导致状态不一致或资源泄漏:
class Shape {
private:
Shape() = default; // 禁止裸构造
protected:
Shape(int id) : id_(id) {} // 子类可调用 protected 构造
int id_;
};
class Circle : public Shape {
Circle() : Shape(1) {} // OK
};
class ShapeFactory {
public:
static std::unique_ptr createCircle() {
return std::make_unique(); // OK:工厂可访问 protected
}
};
- 此处构造函数常设为
protected而非private,以便子类继承并初始化 - 工厂类本身不需要是友元;关键是把构造权限控制在可信范围内(工厂或其子类)
- 若工厂和产品在不同模块,可能需将工厂声明为
friend class ShapeFactory;,但要谨慎——这会破坏封装边界
容易忽略的陷阱:移动语义与私有构造
C++11 后,私有构造函数还会影响移动操作。如果类禁用了拷贝但没显式定义移动构造函数,编译器可能隐式删除移动构造函数,导致 std::make_unique 或返回值优化(RVO)失败。
- 私有默认构造函数 + 未声明移动构造函数 → 类型不可移动,某些工厂返回方式会编译不过
-
解决方法:显式默认移动操作(若语义合理):
Singleton(Singleton&&) = default;,但注意单例通常不应被移动 - 更稳妥的做法是明确删除拷贝、默认移动(或禁止移动),并在文档中说明生命周期由类自身管理
私有构造函数看似简单,但它撬动的是整个对象生命周期的控制权。一旦放开,就很难再收回来;一旦锁死,又得提前想清楚继承、测试、序列化等延伸需求——这点比语法本身更值得花时间推演。










