【C++】限制某个类所能产生的对象数量
2012-08-23 14:37
471 查看
问题来源:假设系统中只有一台打印机,如何把打印机对象数止限定为一个。
或者系统只提供16个可分发出去的文件描述符,如何确保文件描述符对象存在的数目不能超过16个。
在具体的应用过程中,我们可能需要限制某个类所产生的对象数量。
下面我们先从简单的问题的开始。
1.如何允许建立零个对象?
实例化一个对象时,将调用一个构造函数,因而阻止建立某个类的对象,最容易的方法就是把该类的构造函数声明在类的private域。代码示例如下:
2.如何允许建立一个对象?
将类的构造函数声明为private后,每个用户都没有权力建立对象,但实际应用的需求是我们需要建立一个对象,因此我们需要选择性地放松这个限制。
对于声明为private的构造函数,我们可以引入友元函数或成员函数来进行访问,并利用静态成员变量来保证对象的唯一,具体实现代码如下:
上述两种实现思想是一致的,最终都是通过thePrint()函数来完成客户端与系统打印机交互访问的需求。thePrinter()函数的实现有两点值得注意:
1)唯一的Printer对象是位于函数里的静态成员而不是在类中的静态成员。在类中的静态对象有两个缺点,一个总是被构造(和释放),即使不使用该对象;另一个缺点是它的初始化时间不确定。
2)thePrinter()函数没有声明为内联函数,因为内联意味编译器用函数体代替对函数的每一个调用,这样会导致函数内的静态对象在程序内被复制,可能会使程序的静态对象的拷贝超过一个。
上述两种方法,都解决了允许建立一个对象的问题,但无法解决允许建立多个对象的限制问题。
3.如何限制允许建立多个对象?
我们可以换一种思路,不利用友元函数或成员函数来作为建立对象的中介,而引入计数器简单地计算对象的数目,一旦需要太多的对象,就抛出异常。具体代码实现如下:
此法的核心思想就是使用numObjects跟踪Printer对象存在的数量。当构造对象时,它的值就增加,释放对象时,它的值就减少。如果试图构造过多的对象,就会抛出一个TooManyObjects类型的异常。通过maxObjects设置可允许建立对象的最大数目。
以上两种方法基本上可以满足,限制对象数目的要求。但是具体应用中,仍会出现问题,上述两种方法无法解决。如下面代码所示:
利用计数器的方法,上述代码中,都将会产生多个Printer对象,由Printer被作为基类或者被包含于其他类中,导致其他对象的构造时,隐藏构造Printer对象。这主要是计数器方法无法区分对象存在的三种不同环境:只有它们本身;作为其他派生类的基类;被嵌入在更大的对象中。
利用thePrinter()函数的方法,把Printer对象的数量限制为一个,这样做的同时也会让我们每一次运行程序时只能使用一个Printer对象。导致我们不能在程序的不同部分使用不同的Printer对象。如下面伪代码所示:
4.如何解决两种方法存在的问题?
思路:将两种方法结合,将构造函数声明为private,限制其被继承和被包含于其他的类,解决计数器的问题,并提供伪构造函数作为访问对象的接口,并统计对象的个数,来解决限制构造多个对象和程序不同部分使用不同对象的问题。具体代码实现如下:
到目前为止,对于限制对象数目的问题,应该是大功告成。但是仍不能满足工程性上的应用,例如我们有大量像Printer需要限制实例数量的类,就必须一遍又一遍地编写一样的代码,每个类编写一次。作为程序员,应该避免这种重复性的工作。
5.一个具有对象计数功能的基类
针对重复性工作的问题,解决思路是:构造一个具有实例计数功能的基类,让像Printer这样的类从该基类继承,利用派生类对象的构造,需要先构造基类对象的特点,通过隐藏的基类实现计数功能。具体实现如下:
或者系统只提供16个可分发出去的文件描述符,如何确保文件描述符对象存在的数目不能超过16个。
在具体的应用过程中,我们可能需要限制某个类所产生的对象数量。
下面我们先从简单的问题的开始。
1.如何允许建立零个对象?
实例化一个对象时,将调用一个构造函数,因而阻止建立某个类的对象,最容易的方法就是把该类的构造函数声明在类的private域。代码示例如下:
class CantBeInstantiated { private: CantBeInstantiated(); CantBeInstantiated(const CantBeInstantiated&); .... };
2.如何允许建立一个对象?
将类的构造函数声明为private后,每个用户都没有权力建立对象,但实际应用的需求是我们需要建立一个对象,因此我们需要选择性地放松这个限制。
对于声明为private的构造函数,我们可以引入友元函数或成员函数来进行访问,并利用静态成员变量来保证对象的唯一,具体实现代码如下:
//使用友元函数来访问私有构造函数 namespace PrintingStuff { class PrintJob; class Printer { public: void submitJob(const PrintJob& job); void rest(); void performSelfTest(); ... friend Printer& thePrinter(); private: Printer(); Printer(const Printer& rhs); ... }; Printer& thePrinter() { static Printer p; return p; } } using PrintingStuff::thePrinter; thePrinter().reset(); thePrinter().submitJob(buffer);
//使用静态成员函数来访问私有构造函数 class Printer { public: static Printer& thePrinter(); ... private: Printer(); Printer(const Printer& rhs); ... }; Printer& Printer::thePrinter() { static Printer p; return p; } Printer::thePrinter().reset(); Printer::thePrinter().submitJob(buffer);
上述两种实现思想是一致的,最终都是通过thePrint()函数来完成客户端与系统打印机交互访问的需求。thePrinter()函数的实现有两点值得注意:
1)唯一的Printer对象是位于函数里的静态成员而不是在类中的静态成员。在类中的静态对象有两个缺点,一个总是被构造(和释放),即使不使用该对象;另一个缺点是它的初始化时间不确定。
2)thePrinter()函数没有声明为内联函数,因为内联意味编译器用函数体代替对函数的每一个调用,这样会导致函数内的静态对象在程序内被复制,可能会使程序的静态对象的拷贝超过一个。
上述两种方法,都解决了允许建立一个对象的问题,但无法解决允许建立多个对象的限制问题。
3.如何限制允许建立多个对象?
我们可以换一种思路,不利用友元函数或成员函数来作为建立对象的中介,而引入计数器简单地计算对象的数目,一旦需要太多的对象,就抛出异常。具体代码实现如下:
class Printer { public: class TooManyObjects{}; //当需要的对象过多时,抛出的异常类 Printer(); ~Printer(); ... private: static size_t numObjects; static size_t maxObjects; Printer(const Printer& rhs); }; size_t Printer::numObjects = 0; size_t Printer::maxObjects = 10; Printer::Printer() { if(numObjects >= maxObjects) { throw TooManyObjects(); } ... ++numObjects; } Printer::~Printer() { ... --numObjects; }
此法的核心思想就是使用numObjects跟踪Printer对象存在的数量。当构造对象时,它的值就增加,释放对象时,它的值就减少。如果试图构造过多的对象,就会抛出一个TooManyObjects类型的异常。通过maxObjects设置可允许建立对象的最大数目。
以上两种方法基本上可以满足,限制对象数目的要求。但是具体应用中,仍会出现问题,上述两种方法无法解决。如下面代码所示:
class ColorPrinter:public Printer { ... }; Printer p; ColorPrinter cp;
class CPFMachine { private: Printer p; FaxMachine f; CopyMachine c; ... }; CPFMachine m1; CPFMachine m2;
利用计数器的方法,上述代码中,都将会产生多个Printer对象,由Printer被作为基类或者被包含于其他类中,导致其他对象的构造时,隐藏构造Printer对象。这主要是计数器方法无法区分对象存在的三种不同环境:只有它们本身;作为其他派生类的基类;被嵌入在更大的对象中。
利用thePrinter()函数的方法,把Printer对象的数量限制为一个,这样做的同时也会让我们每一次运行程序时只能使用一个Printer对象。导致我们不能在程序的不同部分使用不同的Printer对象。如下面伪代码所示:
建立Printer对象p1; 使用p1; 释放p1; 建立Printer对象p2; 使用p2; 释放p2; ....
4.如何解决两种方法存在的问题?
思路:将两种方法结合,将构造函数声明为private,限制其被继承和被包含于其他的类,解决计数器的问题,并提供伪构造函数作为访问对象的接口,并统计对象的个数,来解决限制构造多个对象和程序不同部分使用不同对象的问题。具体代码实现如下:
class Printer { public: class TooManyObjects{}; //伪构造函数 static Printer* makePrinter(); static Printer* makePrinter(const Printer& rhs); ... private: static size_t numObjects; static const size_t maxObjects; Printer(); Printer(const Printer& rhs); }; size_t Printer::numObjects = 0; const size_t Printer::maxObjects = 10; Printer::Printer() { if(numObjects >= maxObjects) { throw TooManyObjects(); } ... } Printer::Printer(const Printer& rhs) { if(numObjects >= maxObjects) { throw TooManyObjects(); } ... } Printer* Printer:makePrinter() { return new Printer; } Printer* Printer::makePrinter(const Printer& rhs) { return new Printer(rhs); } Printer *p1 = Printer::makePrinter();
到目前为止,对于限制对象数目的问题,应该是大功告成。但是仍不能满足工程性上的应用,例如我们有大量像Printer需要限制实例数量的类,就必须一遍又一遍地编写一样的代码,每个类编写一次。作为程序员,应该避免这种重复性的工作。
5.一个具有对象计数功能的基类
针对重复性工作的问题,解决思路是:构造一个具有实例计数功能的基类,让像Printer这样的类从该基类继承,利用派生类对象的构造,需要先构造基类对象的特点,通过隐藏的基类实现计数功能。具体实现如下:
template<class BeingCounted> class Counted { public: class TooManyObjects{}; static int objectCount() { return numObjects; } protected: Counted(); Counted(const Counted& rhs); ~Counted() { --numObjects; } private: static int numObjects; static const size_t maxObjects; void init(); }; template<class BeingCounted> Counted<BeingCounted>::Counted() { init(); } template<BeingCounted> Counted<BeingCounted>::Counted(const Counted<BeingCounted>&) { init(); } template<class BeingCounted> void Counted<BeingCounted>::init() { if(numObjects >= maxObjects) throw TooManyObjects(); ++numObjects; } class Printer::private Counted<Printer> { public: static Printer* makePrinter(); static Printer* makePrinter(const Printer& rhs); ~Printer(); void submitJob(const PrintJob& job); void reset(); void performSelfTest(); ... using Counted<Printer>::objectCount; using Counted<Printer>::TooManyObjects; private: Printer(); Printer(const Printer& rhs); };
相关文章推荐
- More Effective C++ 条款26 限制某个class所能产生的对象数量
- c++限制某个class所能产生对象数量的方法
- More Effective C++----(26)限制某个类所能产生的对象数量
- 《More Effective C++》条款26:限制某个Class所能产生的对象数量
- 10.限制某个类所能产生的对象数量——之一
- effective C++——限制类所能产生的对象数量
- 条款26:限制某个class所能产生的对象数量
- 【more effective c++读书笔记】【第5章】技术(2)——限制某个class所能产生的对象数量
- 【more effective c++读书笔记】【第5章】技术(2)——限制某个class所能产生的对象数量
- More Effective C++(条款26:限制某个class所能产生的对象个数)
- 限制某个类所能产生的对象数量
- 技术(2)—限制某个class所能产生的对象数量
- 11.限制某个类所能产生的对象数量——之二
- 【M26】限制某个class所能产生的对象数量
- 条款二十六:限制某个class所能产生的对象的数量
- More Effective C++ 阅读笔记(十二)--怎样限制实例化对象的数量
- more effective C++设计模式限制对象产生
- C++ 限制类对象的数量的方法
- More Effective C++ (限制类的对象数量)
- C++对象数量跟踪限制