目录
[1. HeapOnly(只能在堆上创建的对象)](#1. HeapOnly(只能在堆上创建的对象))
方法二:c++11方法,通过private限制构造,通过delete限制拷贝构造和赋值
[2. StackOnly(只能在栈上创建的对象)](#2. StackOnly(只能在栈上创建的对象))
[方法:operator new 和构造函数的访问权限来限制对象的创建方式](#方法:operator new 和构造函数的访问权限来限制对象的创建方式)
方法一:c++11玩法,通过delete来禁止拷贝构造和赋值
[方法二:C++11 final 关键字](#方法二:C++11 final 关键字)
[方法三:私有构造函数 + 虚继承(传统方法)](#方法三:私有构造函数 + 虚继承(传统方法))
[1. 饿汉模式(Hungry Initialization)](#1. 饿汉模式(Hungry Initialization))
[2. 懒汉模式(Lazy Initialization)](#2. 懒汉模式(Lazy Initialization))
一、堆/栈专属类设计
1. HeapOnly(只能在堆上创建的对象)
方法一:通过private限制析构函数
代码:
cpp
class HeapOnly {
public:
void Destroy()
{
delete this; // 手动释放堆对象
}
private:
~HeapOnly() {} // 析构函数私有化
};
int main()
{
HeapOnly hp1; // (1) 直接栈对象 - 编译错误
static HeapOnly hp2; // (2) 静态对象 - 编译错误
HeapOnly* hp3 = new HeapOnly; // (3) 堆对象 - 允许
delete hp3; // (4) 直接delete - 编译错误
hp3->Destroy(); // (5) 必须通过Destroy释放
return 0;
}
下面会展示三个报错,并且解答原因

(1) HeapOnly hp1
(栈对象)
栈对象的析构由编译器在作用域结束时自动调用,但 ~HeapOnly() 是私有的,编译器无法访问
(2) static HeapOnly hp2
(静态对象)
静态对象的生命周期持续到程序结束,由编译器自动析构,但析构函数私有,编译器无法调用
(3) HeapOnly* hp3 = new HeapOnly
(堆对象)
new 只调用构造函数(默认是 public 的),析构函数仅在 delete 时调用,此时由用户通过 Destroy()
间接调用
(4) delete hp3
(直接 delete)
delete 会尝试调用析构函数,但析构函数是私有的,外部代码无法访问
(5) hp3->Destroy()
(正确释放方式)
Destroy() 是成员函数,可以访问私有析构函数,内部调用 delete this 完成释放
方法二:c++11方法,通过private限制构造,通过delete限制拷贝构造和赋值
代码:
cpp
class HeapOnly {
public:
static HeapOnly* CreateObj()
{ // 唯一创建接口
return new HeapOnly;
}
private:
HeapOnly() {} // 构造函数私有化
HeapOnly(const HeapOnly&) = delete; // 禁用拷贝构造
HeapOnly& operator=(const HeapOnly&) = delete; // 禁用赋值
};
int main()
{
// HeapOnly hp1; // (1) 栈对象 - 编译错误
// static HeapOnly hp2; // (2) 静态对象 - 编译错误
// HeapOnly* hp3 = new HeapOnly; // (3) 直接new - 编译错误
HeapOnly* hp3 = HeapOnly::CreateObj(); // (4) 唯一合法创建方式
// HeapOnly copy(*hp3); // (5) 拷贝对象 - 编译错误
return 0;
}
下面会展示四个报错,并且解答原因

(1) HeapOnly hp1
(栈对象)
构造函数是私有的,外部无法直接调用
(2) static HeapOnly hp2
(静态对象)
静态对象需要调用构造函数,但构造函数私有,报错与 hp1 相同
(3) HeapOnly* hp3 = new HeapOnly
(直接new)
虽然 new 可以绕过析构限制,但构造函数私有
(4) HeapOnly* hp3 = HeapOnly::CreateObj()
静态成员函数可以访问私有构造函数,返回堆分配对象指针)
(5) HeapOnly copy(*hp3)
(拷贝对象)
拷贝构造函数被 = delete 显式删除
2. StackOnly(只能在栈上创建的对象)
方法: operator new
和构造函数的访问权限来限制对象的创建方式
代码:
cpp
class StackOnly {
public:
static StackOnly CreateObj()
{
StackOnly st; // 合法:成员函数可访问私有构造
return st; // 返回值可能触发拷贝构造(需确保可用)
}
private:
StackOnly() {} // 私有构造函数
void* operator new(size_t) = delete; // 禁用堆分配
};
int main()
{
// StackOnly hp1; // (1) 直接栈对象 - 编译错误
// static StackOnly hp2; // (2) 静态对象 - 编译错误
// StackOnly* hp3 = new StackOnly; // (3) 堆对象 - 编译错误
StackOnly obj = StackOnly::CreateObj(); // (4) 合法栈对象
StackOnly copy(obj); // (5) 拷贝构造 - 依赖编译器实现
// StackOnly* hp4 = new StackOnly(obj); // (6) 堆拷贝 - 编译错误
return 0;
}
下面会展示四个报错,并且解答原因

(1) StackOnly hp1
(直接栈对象)
构造函数是私有的,外部无法直接调用
(2) static StackOnly hp2
(静态对象)
静态对象需要调用私有构造函数
(3) StackOnly* hp3 = new StackOnly
(堆对象)
operator new 被显式删除
(4) StackOnly obj = StackOnly::CreateObj()
静态方法 CreateObj() 可访问私有构造返回栈对象(可能触发拷贝/移动构造)
(5) StackOnly copy(obj)
(拷贝构造)
原代码未显式定义拷贝构造,如果编译器自动生成拷贝构造,则能编译通过,但违背了"栈专属"的设计初衷
(6) new StackOnly(obj)
(堆拷贝)
即使拷贝构造可用,operator new 仍被禁用,报错与 (3) 相同
3.Copyban(不能copy的对象)
代码:
方法一:c++11玩法,通过delete来禁止拷贝构造和赋值
cpp
class copyban
{
public:
copyban()
:a(0)
{}
copyban(const copyban& t)=delete;
copyban& operator =(const copyban&)=delete;
int a = 0;
};
int main()
{
copyban s1;
copyban s2;
copyban s1(0);
copyban s2(s1);
return 0
}
结果:

方法二:通过private:来实现限制拷贝构造和赋值
代码:
cpp
class copyban
{
public:
copyban()
:a(0)
{}
private:
copyban(const copyban& t);
copyban& operator =(const copyban&);
int a = 0;
};
int main()
{
copyban s1;
copyban s2;
copyban s1(0);
copyban s2(s1);
return 0
}
结果:
cpp
class NonInherit {
public:
static NonInherit GetInstance() {
return NonInherit(); // 通过静态方法返回临时对象
}
private:
NonInherit() {} // 私有构造函数
};
4.NonInherit(不能被继承的类)
方法一:private限制构造,导致派生类到不到基类的构造
代码:
cpp
class NonInherit {
public:
static NonInherit GetInstance() {
return NonInherit(); // 通过静态方法返回临时对象
}
private:
NonInherit() {} // 私有构造函数
};
上文的漏洞代码:
cpp
class Child : public NonInherit { // 可以继承
public:
Child() : NonInherit() {} // 错误:无法访问基类私有构造
};
// 但通过中间层可以破解:
class DeceptiveChild : public NonInherit {
public:
static DeceptiveChild Create() {
return DeceptiveChild(); // 调用默认构造(隐式调用基类构造)
}
private:
DeceptiveChild() = default; // 隐式调用基类构造
};
方法二:C++11 final
关键字
代码:
cpp
class A final
{
//...
};
方法三:私有构造函数 + 虚继承(传统方法)
代码:
cpp
class NonInheritableBase {
private:
NonInheritableBase() = default;
friend class NonInherit; // 仅允许友元类继承
};
class NonInherit : virtual NonInheritableBase { // 虚继承是关键
public:
static NonInherit GetInstance() {
return NonInherit();
}
private:
NonInherit() = default;
};
// 任何尝试继承的行为:
class Child : public NonInherit {
public:
Child() {} // 错误:无法调用NonInheritableBase的私有构造
};
二、单例模式实现
简单理解就是
饿汉模式:类加载时就立即创建类实例化对象("饿",迫不及待)
懒汉模式:延迟初始化,只有在第一次使用时才创建类实例化对象("懒",用的时候再弄)
1. 饿汉模式(Hungry Initialization)
代码:
cpp
namespace hungry {
class Singleton {
public:
static Singleton& GetInstance() {
return _sinst; // 直接返回预先创建好的实例
}
// ...其他成员函数...
private:
Singleton() {} // 私有构造函数
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
map<string, string> _dict;
static Singleton _sinst; // 静态成员变量
};
Singleton Singleton::_sinst; // 程序启动时即初始化
}
特点:
-
立即初始化
- 单例对象在
main()
函数执行前(全局静态变量初始化阶段)就已经创建 - 通过静态成员变量
_sinst
实现
- 单例对象在
-
不可拷贝
- 禁用拷贝构造和赋值操作
2. 懒汉模式(Lazy Initialization)
代码:
cpp
namespace lazy {
class Singleton {
public:
static Singleton& GetInstance() {
if (_psinst == nullptr) { // 第一次调用时创建
_psinst = new Singleton;
}
return *_psinst;
}
static void DelInstance() { // 手动释放
delete _psinst;
_psinst = nullptr;
}
private:
Singleton() = default;
~Singleton() { /* 持久化操作 */ }
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
static Singleton* _psinst; // 指针形式
static GC _gc; // 辅助垃圾回收
};
Singleton* Singleton::_psinst = nullptr; // 初始为空
Singleton::GC Singleton::_gc; // 静态成员
}
特点
-
延迟初始化
- 第一次调用
GetInstance()
时才创建对象
- 第一次调用
-
手动/自动释放
-
提供
DelInstance()
手动释放 -
通过嵌套类
GC
在程序结束时自动释放(利用静态成员析构)
-