条款26:限制某个class所能产生的对象的数量
1️⃣ 允许零个或一个对象
- 定义
- 每当即将产生一个对象,我们确知一件事情:会有一个
constructor
被调用。 - “阻止某个
class
产出对象”的最简单方法就是将其<font style="background-color:#FBDE28;">constructors</font>
声明为<font style="background-color:#FBDE28;">private</font>
- 每当即将产生一个对象,我们确知一件事情:会有一个
2️⃣ 问题的引入
假设我想为打印机设计一个
class
,我希望设下“只能存在一台打印机”的约束。我们可以将”打印机对象“封装在某个函数内,如此一来每个人都能够取用打印机,但只有唯一一个打印机对象会被产生。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19class PrintJob; //前置声明
class Printer {
public:
void submitJob(const PrintJob& job);
void reset ();
void performSelfTest ();
...
friend Printer& thePrinter();
private:
Printer();
Printer(const Printer& rhs);
};
Printer& thePrinter ()
{
static Printerp; //唯一的一个打印机对象。
return p;
}- 类的设计思想
- 第一,
Printer class
的constructor
属性是private
,可以压制对象的诞生。 - 第二,全局函数
thePrinter
被声明为此class
的一个friend
,致使thePrinter
不受private constructors
的约束。 - 第三,
thePrinter
内含一个static Printer
对象,意思是只有一个Printer
对象会被产生出来。
- 第一,
- 类的设计思想
3️⃣ 值得探讨的地方
第一点
- 形成唯一一个
Printer
对象的,是函数中的static
对象而非class
中的static
对象- 优点一
- “
class
拥有一个static
对象”的意思是:即使从未被用到,它也会被构造(及析构)。 - “函数拥有一个
static
对象”的意思是:此对象在函数第一次被调用时才产生。
- “
- 优点二
function static
的初始化时机:在该函数第一次被调用时,并且在该static
被定义处。至于一个class static
(或是global static
)则不一定在什么时候初始化。- C++对于“同一编译单元内的
statics
”的初始化顺序是有提出一些保证的,但对于“不同编译单元内的statics
”的初始化顺序没有任何说明。
- 优点一
第二点
- 函数的”
static
对象“与inlining
的互动。- 为什么不被不将
thePrinter
申明成inline
? inline
对于non-member functions
意味着这个函数有内部连接(internal linkage
)。- 函数如果带有内部连接,可能会在程序中被复制,也就是说程序的目标代码(
object code
)可能会对带有内部连接的函数复制一份以上的代码,而此复制行为也包括函数内的static
对象。 - 结果呢,如果你有一个
<font style="background-color:#FBDE28;">inline non-member function</font>
并于其中内含一个<font style="background-color:#FBDE28;">local static</font>
对象,你的程序可能会拥有多份该<font style="background-color:#FBDE28;">static</font>
对象的副本。 - 所以,千万不要产生内含
local static
对象的inline non-member functions
。
- 函数如果带有内部连接,可能会在程序中被复制,也就是说程序的目标代码(
- 为什么不被不将
4️⃣ 对象计数
目的
- 利用
numObjects
来追踪记录目前存在多少个Printer
对象。这个数值将在constructor
中累加,并在destructor
中递减。如果外界企图构造太多Printer
对象,我们就抛出一个类型为TooManyObjects
的exception
- 利用
案例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28class Printer {
public:
class TooManyObjects (); //当外界申请太多对象时,
// 抛出这种 exceptionclass。
Printer();
~Printer();
...
private:
static size_t numObjects;
Printer(const Printer&rhs); //有着“打印机个数永远为 1”的限制,
//所以决不允许复制行为。
};
size_t Printer::numObjects = 0;
Printer::Printer()
{
if (numObjects >= 1) {
throw TooManyObject();
}
proceed with normal construction here;
++numObjects;
}
Printer::~Printer()
{
perform normal destruction here;
--numobjects;
}
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 GYu的妙妙屋!