限制对象的产生个数
限制对象产生的个数是我们在程序设计中经常遇到的问题,有的时候我们的系统只有一台打印机,所以我们只能存在一个打印机对象。我们的文件描述符有限,所以我们也要限制文件描述符产生的数量。
单例模式设计
以一个打印机对象的设计为例子:
class PrintJob;
class Printer
{
public:
friend Printer& thePrinter();
private:
Printer();
Printer(const Printer&);
Printer& operator=(const Printer&);
}
Printer& thePrinter();
{
static Printer;
return p;
}
这里我们把Printer对象放到友元函数中,并放在相应的命名空间是合理,你也可以把thePrinter声明为类的静态成员函数。这里值得注意的是两个地方:
1.把static放在函数内而不是类里面,可以在用的时候才定义,不用的时候就不用定义了。
2.如果放在类里面,不同编译单元之间的静态变量初始顺序没有保证,使用的时候兑现可能不存在,所以这个设计是有原因的。
一种可能想出来的替换方案是在类内部维护一个静态变量统计产生的对象个数,当超过一个对象时抛出一个异常。但是这种做法是有问题的:
1.一个对象的存在可能是由于被继承。
2.定义一个对象。
3.是一个大的类的成员对象
所以很多时候我们不容易察觉我们是否只使用的一个对象。
这里引出一种设计带有private构造函数的类不能够被继承(注意uncopyable的复制构造函数 以及复制运算符是private 但是构造函数是public的)
所以当我们不允许对象被复制但是又要产生多个对象的时候,我们可以采用以下设计:
class FSA
{
public
static FSA* makeFSA();
static FSA* makeFSA(const FSA&)
private:
FSA();
FSA(const FSA&);
}
FSA* FSA::makeFSA()
{
return new FSA();
}
FSA* FSA::makeFSA(const FSA&rhs)
{
return new FSA(rhs);
}
这里值得注意的是我们最好在makeFSA返回的指针对象上用智能指针包裹,避免内存的泄露。
我们知道一个拥有private构造函数的类不能被继承,并且不能作为其他类的成员,所以我们利用这种技术来限制有限多个对象的产生,具体的代码如下:
class Printer
{
public:
class tooManyObjects{};
static Printer* makePrinter();//伪构造函数
~Printer();
private:
static const int maxNumObjetcs=10;
static int numObjects;
Printer();
Printer(const Printer&);
}
size_t Printer::numObjects=0;
const size_t Printer::maxNumObjects;
Printer* Printer::makePrinter()
{
return new Printer();
}
Printer::printer
{
if(numObjects>=maxNumObjects)
throw tooManyObjects();
....
numObjects++;
}
~Printer
{
numObjects--;
}
这里当我们的maxNumObjects是1的时候,我们就有了另一种单例模式的写法,但是这种写法允许对象的生生灭灭。
一个用来计算对象个数的baseclass
上面的类已经可以运用来处理对象的计数问题,但是如果我们有多个class都需要对象计数,这时候我们就不能够为每一个class都实现出这种细节了。一个好的方式是使用对象计数的base class.
一个典型的实现如下:
template <class BeingCounted>
Counted
{
public:
class TooManyObjects{};
protected://注意只能使用protected,这样这个类才能被继承
Counted()
Counted(const Counted<BeingCounted>&);
~Counted() {--NumObjects};
private:
static int NumObjects;
static const size_t MaxObjects;
void init(){ if(numObjects>MaxObjects) throw TooManyObjects();};
}
template<BeingCounted>
int Counted<BeingCounted>::NumObjects;
当其他的类在使用这个函数的时候需要注意的几点,如果需要使用Counted中的函数需要手动using声明,第二个需要声明Counted<Printer>::MaxObjects=10
在实现文件中。第三是使用private继承,因为我们是利用这个class来实现某个东西。