Singleton的C++实现详解

本文详细介绍了C++中实现Singleton模式的步骤和注意事项,包括保护构造函数、使用静态成员变量保存实例、线程安全的实现等。通过模板类和宏定义,使Singleton模式更加通用,同时也提供了Singleton类个性化的扩展接口。
摘要由CSDN通过智能技术生成

Singleton

The Singleton Pattern: ensures a class has only one instance, and provides a global point of access to it.
只有一个实例的类,如下是若干考虑:
 首先,要产生类实例,需要调用构造函数。为了防止用户申明或者new一个类的实例,我们可以把这个类的构造函数设置为protected或者private,那么用户申明或者new就不可能编译通过,当然,delete也是不允许的,也申明为protected或者private
 可是,我们在哪里创建类实例呢?虽然外部不能创建类的对象,但是类的内部,是可以调用构造函数,从而可以创建类实例的。我们给类的外部提供一个方法GetInstance()。它在没有类实例时创建类实例并返回实例(指针或引用);在有实例时,直接返回已有实例。这样我们就需要保存实例的指针以备GetInstance()使用,该指针也应该定义在类上,否则在没有类实例之前,怎么给这个成员变量赋值呢?如此,第一个版本得到:
  class   Singleton  
  {  
  public:  
          static   Singleton&   Instance()  
          {  
                  if   (!si_instance)  
                  {  
                          si_instance   =   new   Singleton;  
                  }  
                  return   *si_instance;  
          }  
  private:  
          //禁止外部构造函数调用
          Singleton(){}
          //对象静态指针,用于保存创建的对象
          static   Singleton*   si_instance; //声明静态数据成员
  };
  Singleton* Singleton::si_instance=0; //定义并初始化全局存贮,局部作用的静态数据成员
 Static用在类外:
 static和extern都是變量的存贮类型,申明為static的變量,不能被其他文件(指目标文件)引用,extern可以被本文件和其他文件引用(指目标文件)。不能同時使用它們申明同一個變量。它們的共同點是存放位置都在程序的static   memory中(全局存贮)。
 其中static可以用于局部變量的申明,此時每次Call   Function時,其中的Static局部變量的值不執行初始化,即保留上一次引用結束後的值。
 extern是default的申明。  
 不提倡使用static局部變量。  
 具體的使用還與編譯器有關,以上的說明建立在ANSI   C所定義的C   Complier基礎上。
 CPP文件产生目标文件,显然,CPP文件include的头文件中的static或extern变量在CPP中仍然有效(非只在头文件中有效)。链接时,static变量只在本obj内可引用,而extern则在所有obj内可引用(这样就可能会重名,出现重定义错误,所以才引入static关键字)。对于静态全局函数,也是用于限制这个全局函数在本obj文件中。
 Static用在类定义中:
 类是类型的定义。类中的所有成员的定义均是一个申明,说明这个类的内部构成。只有产生类的实例的代码,才需要为类的成员分配存贮空间,或在栈上,或在堆中。
 为处理定义在类上的变量,我们用static修饰该成员。这时static的语义是该成员是一个extern类型的全局变量。由于类定义是申明,比如在类fun中申明static int i,而i并没有被定义(产生实例),我们需要在类的外部定义并初始化fun::i,这就是为什么类中的静态变量必须初始化,且必须在类外初始化。
 然而,这又带来了额外的问题,那就是如果在多个CPP都包含了类fun定义文件,那么对fun::i的定义并初始化语句就会在多个CPP文件中出现,链接就无法通过!
 这就是为什么要区分头文件和CPP文件的原因。我们把“申明”写在头文件中,把“定义”(也就是会产生实例的代码)写在CPP文件中,因为我们从不include CPP文件,所以,定义fun::i只有一次!!!这个原则同样适用于类的方法。类的方法f()如果在类的外部实现,也应该写在CPP中,否则当头文件被多个CPP文件引用时,就会出错。如果把成员函数体直接写在类中,那么不会有问题,尽管多个包含类头文件的CPP文件的obj都产生了fun::f(),但是,这个函数定义的作用域不会超出这个类的代码块,因此不会冲突。编译时实际上产生了这个函数的多个副本,每个副本只在局部作用。链接时用到的副本会写入exe文件,甚至被处理为内联函数。相对的,如果把fun::f()写在类的实现CPP文件中,那么就只在编译时产生一个fun::f()代码,看起来编译会较少花费时间。
 对于类的成员函数,用static修饰时,表示它是一个定义在类上的方法,函数并没有存贮类别一说,这个寒暑不需要传递this指针就可以调用,即通过类名就可以引用,当然,如果创建了类对象,通过对象也可以引用。普通的成员函数则需要通过this指针来使用(实际上是传递了this指针给那个函数)
 小结:在定义性代码(类外的代码)中,static保证修饰对象生存期为程序运行全过程,在代码块中定义,作用域在代码块中,在代码块外(全局定义),作用域是obj文件
在申明性代码中(类中),static保证修饰对象的生存期是程序执行全过程,作用域是全局,因为是申明,不是定义,所以对于成员变量需要在类外部定义全局的成员,对于成员函数在外部和内部定义都可以,因为static仅说明不传递this指针给该函数。
 这个版本有一个问题,就是对象创建了,可是在哪里删除这个对象呢?我们是在类的内部new对象的,外部没有new,那么外部也不应该去delete。Si_instance是一个静态变量,用来保存指针ÿ

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

RockTec

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值