例如你在系统中只有一台打印机,所以你想用某种方式把打印机对象数目限定为一个。或者你仅仅取得 16 个可分发出去的文件描述符,所以应该确保文件描述符对象存在的数目不能超过 16 个。你如何能够做到这些呢?如何去限制对象的数量呢?
每次实例化一个对象时,我们很确切地知道一件事情:“将调用一个构造函数。”事实确实这样,阻止建立某个类的对象,最容易的方法就是把该类的构造函数声明在类的 private
域或者声明为delete:
class CantBeInstantiated
{
private:
CantBeInstantiated();
CantBeInstantiated(const CantBeInstantiated&);
...
};
或者:
class CantBeInstantiated
{
public:
CantBeInstantiated() = delete;
CantBeInstantiated(const CantBeInstantiated&) = delete;
...
};
这样做以后,每个人都没有权利建立对象,我们能够有选择性地放松这个限制。例如如果想为打印机建立类,但是要遵守我们只有一个对象可以用的约束,我们应该把打印机对象封装在一个函数内,以便让每一个人都能够访问打印机,但是只有一个打印机对象被建立:
class 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 Printer p; // 单个打印机对象
return p;
}
这个设计由三个部分组成,
第一、Printer
类的构造函数是 private
。这样能阻止建立对象。
第二、全局函数 thePrinter
被声明为类的友元,让 thePrinter
避免私有构造函数引起的限制。
最后 thePrinter
包含一个静态 Printer
对象,这意味着只有一个对象被建立。 客户端代码无论何时要与系统的打印机进行交互访问,它都要使用 thePrinter
函数:
class PrintJob
{
public:
PrintJob(const string& whatToPrint);
...
};
string buffer;
... //填充 buffer
thePrinter().reset();
thePrinter().submitJob(buffer);
当然你感到 thePrinter
使用全局命名空间完全是多余的,你可能会想把所有与打印有关的功能都放到 Printer
类里。这很简单,只要在 Prihter
类中声明 thePrinter
为静态函数,然后把它放在你想放的位置。就不再需要友元声明了。使用静态函数,如下所示:
class Printer
{
public:
static Printer& thePrinter();
...
private:
Printer();
Printer(const Printer& rhs);
...
};
Printer& Printer::thePrinter()
{
static Printer p;
return p;
}
用户使用 printer 时有些繁琐:
Printer::thePrinter().reset();
Printer::thePrinter().submitJob(buffer);
另一种方法是把 thePrinter
移出全局域,放入 namespace
(命名空间)。
把 Printer
类和thePrinter
函数放入一个命名空间,我们就不用担心别人也会使用 Printer
和 thePrinter
名字;命名空间能够防止命名冲突。
如下所示,我们把 Printer
、thePrinter
放入叫做 PrintingStuff
的命名空间里:
namespace PrintingStuff
{
class Printer // 在命名空间PrintingStuff 中的类
{
public:
void submitJob(const PrintJob& job);