每次实例化一个对象时,我们很确切地知道一件事情:“将调用一个构造函数。”事实确实这样,阻止建立某个类的对象,最容易的方法就是把该类的构造函数声明在类的private域:
class CantBeInstantiated {
private:
CantBeInstantiated();
CantBeInstantiated(const CantBeInstantiated&);
...
};
这样做以后,每个人都没有权力建立对象,我们能够有选择性地放松这个限制。例如如果想为打印机建立类,但是要遵守我们只有一个对象可用的约束,我们应把打印机对象封装在一个函数内,以便让每个人都能访问打印机,但是只有一个打印机对象被建立。:
class PrintJob; // forward 声明
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使用全局命名空间完全是多余的。“全局函数看起来象全局变量,但是全局变量是gauche(笨拙的),我们想把所有与打印有关的功能都放到Printer类里。”这很简单,只要在Prihter类中声明thePrinter为静态函数,然后把它放在我们想放的位置。就不再需要友元声明了。使用静态函数,如下所示:
class Printer {
public:
static Printer& thePrinter();
...
private:
Printer();
Printer(const Printer& rhs);
...
};
Printer& Printer::thePrinter() [Page]
{
static Printer p;
return p;
}
用户使用printer时有些繁琐:
Printer::thePrinter().reset();
Printer::thePrinter().submitJob(buffer);
另一种方法是把thePrinter移出全局域,放入namespace(命名空间)。命名空间是C++一个较新的特性。任何能在全局域声明东西也能在命名空间里声明。包括类、结构、函数、变量、对象、typedef等等。把它们放入命名空间并不影响它们的行为特性,不过能够防止在不同命名空间里的实体发生命名冲突。把Printer类和thePrinter函数放入一个命名空间,我们就不用担心别人也会使用Printer和thePrinter名字;命名空间能够防止命名冲突。
命名空间从句法上来看有些象类,但是它没有public、protected或private域。所有都是public。如下所示,我们把Printer、thePrinter放入叫做PrintingStuff的命名空间里:
namespace PrintingStuff {
class Printer { // 在命名空间
public: // PrintingStuff中的类
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;
}
}
// 命名空间到此结束