关于C++单实例类的讨论

      最近在改良计算器 abacus 的代码,想把其中的一些类限制为单实例(即只能创建一个对象)。其实我个人并不喜欢设计模式,因为这些模式比较复杂,而且实现代码臃肿。C++ 要实现的机制通常是两个选择:要么由程序员来完成,要么由机器来完成。但 C++ 是为开发大型软件而设计的,所以它总是假定人是容易犯错的,比如名字空间。

      好了,闲话少叙,单实例模式在设计模式的书中已经有很多的讨论,我今天说的是我的感受,而且我对于书上的实现不是很满意,做了一个小小的变动。

     单实例模式要解决的问题是如何限制一个类只能创建唯一的对象,由于对象在创建的时候会自动调用构造函数,所以只要把构造函数声明为 private 就可以防止对类的随意构造,而需要的这个唯一的对象则可以这样创建: 为类添加一个 private 的 static 指针(以保存本类的唯一实例的地址),然后再添加一个公用的 static 的成员函数 GetInstance(),在函数内部检查指针是否为空,是则为此指针 new 一个对象就并返回这个指针。实现代码如下:


class Singleton
{
private:  // 私有化构造函数
        Singleton(){}
        ~Singleton(){}

public:   // 提供外部访问唯一对象的方法
       static Singleton *GetInstance()
       {
               if(!pInstance) pInstance = new Singleton;
               return pInstance;
       }
       static void DestroyInstance(){if(pInstance) {delete pInstance;}}

private:
       static Singleton *pInstance;
};

Singleton* Singleton::pInstance = NULL; //类体外初始化静态成员
       这就是设计模式的书上所讲的方法,但是这样有一些问题,最严重的是如何程序中有好多类都需要限制单实例(比如计算器 abacus 中的词法分析器、语法分析器、计算器、日志服务等),那么不得不为每一个类都添加这样的逻辑,这想必是一件枯燥无味的事。最好是将做一个基类,使得从此类继承下来的类都只能创建一个对象,这个想法不错,利用 C++ 提供的类模板,可以写出如下的实现:



#define DECLARE_SINGLETON(type) \
protected: \
        type();   \
        ~type();

template<class T>
class Singleton
{
DECLARE_SINGLETON(Singleton)

public:   // 提供外部访问唯一对象的方法
       static T *GetInstance()
       {
               if(!pInstance) pInstance = new Singleton;
               return pInstance;
       }
       static void DestroyInstance(){if(pInstance) {delete pInstance;}}

private:
       static T* pInstance;
};

template<class T>
Singleton* Singleton<T>::pInstance = NULL; //类体外初始化静态成员
       最上面那个宏的作用是把某个类的默认构造函数声明为受保护的,然后把自己需要限制单实例的类从它继承,像下面这样使用:



#include "Singleton.h"

class MyClass : public Singleton<MyClass>
{
DECLARE_SINGLETON(MyClass)

public:
      // member functions.......

private:
      // member data......
};
      这样似乎比较完美了,但是有一个瑕疵,就是它把默认的构造函数私有化了,顺便把构造函数的函数体也写成空的了,如果我真想在构造函数中完成一些初始化的工作,又该怎么办呢,有两个思路,一是不要那个 DECLARE_SINGLETON 的宏声明,自己手动把类的构造函数声明为 private,这样的缺点是如果忘记了这一点,而写成了 public 的话,那么前面的工作全部白费了;另一个思路是强制提供一个初始化函数,在DECLARE_SINGLETON 所声明的默认构造函数体中调用此初始化函数,然后在自己的类内部实现这个初始化函数,这样倒是可以防止前面的问题,但代价是自己的类要做更多的工作。


<全文完>

你可能感兴趣的:(单例,单实例,唯一对象)