单例模式
来源:互联网 发布:网络舆情的最新发展 编辑:程序博客网 时间:2024/06/08 02:33
单例模式的意思就是只有一个实例。单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。这个类称为单例类。
单例模式的要点有三个:一是某个类只能有一个实例;二是它必须自行创建这个实例;三是它必须自行向整个系统提供这个实例。
C++单例模式有许多种实现方法,在C++中,甚至可以直接用一个全局变量做到这一点,但这样的代码显得很不优雅。《设计模式》一书中给出了一种很不错的实现,定义一个单例类,使用类的私有静态指针变量指向类的唯一实例,并用一个公有静态方法获取该实例。
如下:单例模式程序一:
Singleton.h文件:class CSingleTon{private:CSingleTon(); //构造函数为私有的public:~CSingleTon();//析构函数是公有的public:static CSingleTon* GetInstance();//用来获取实例,公有int GetVar();//获取m_num的值void SetVar(int var);//设置m_num的值void Print(); //在控制台上打印m_num的值private:static CSingleTon *m_pInstance; //类的唯一实例,私有int m_var;};
Singleton.cpp#include <iostream>using namespace std;#include "singleton.h"CSingleTon *CSingleTon::m_pInstance = CSingleTon::GetInstance();//静态成员变量的初始化CSingleTon::CSingleTon(){m_var = 0;}CSingleTon::~CSingleTon(){if(m_pInstance != NULL)delete m_pInstance;}void CSingleTon::SetVar(int var){m_var = var;}int CSingleTon::GetVar(){return m_var;}CSingleTon* CSingleTon::GetInstance(){if(m_pInstance == NULL){m_pInstance = new CSingleTon();}return m_pInstance;}void CSingleTon::Print(){cout<<m_var<<endl;}
Main.cpp#include <iostream>using namespace std;#include "singleton.h"int main(void){CSingleTon *tonfir = CSingleTon::GetInstance();CSingleTon *tonsec = CSingleTon::GetInstance();printf("%p\n%p\n", tonfir, tonsec); //打印两个单例类对象指针的地址tonfir->Print();tonfir->SetVar(5);tonsec->Print();delete tonfir; //调用析构函数delete tonsec;//其实这句话可以不写,因为tonfir和tonsec指向的是同一个对象return 0;}
该单例类的特征:
1.它有一个唯一实例的静态指针变量m_pInstance,并且是私有的;
2.它有一个公有函数,用于获取这个唯一实例,并在需要的时候创建该实例;
3.它的构造函数是私有的,这样就不能在别处创建该类的实例
大多时候,这样的实现都不会出现问题。有经验的读者可能会问,m_pInstance指向的空间什么时候释放呢?更严重的问题是,这个实例的析构操作什么时候执行?如果在类的析构行为中有必须的操作,比如关闭文件,释放外部资源,那么上面所示的代码无法实现这个要求。我们需要一种方法,正常地删除该实例。
可以在程序结束时调用GetInstance并对返回的指针调用delete操作。这样做可以实现功能,但是不仅很丑陋,而且容易出错。因为这样的附加代码很容易被忘记,而且也很难保证在delete之后,没有代码再调用GetInstance函数。
一个妥善的方法是让这个类自己知道在合适的时候把自己删除。或者说把删除自己的操作挂在系统中的某个合适的点上,使其在恰当的时候自动被执行。
我们知道,程序在结束的时候,系统会自动析构所有的全局变量。事实上,系统也会析构所有的类的静态成员变量,就像这些静态成员也是全局变量一样。利用这个特征,我们可以在C++单例模式类中定义一个这样的静态成员变量,而它的唯一工作就是在析构函数中删除单例类的实例。如下面的代码中的CGarbo类(Garbo意为垃圾工人)
Singleton.h#pragma onceclass CSingleTon{private:CSingleTon(); //构造函数为私有的public: //析构函数要是公有的~CSingleTon();private:static CSingleTon *m_pInstance; //类的唯一实例class CGarbo//内部类,该类的唯一工作是在析构函数中删除CSingleTon的实例{public:~CGarbo(){//if(CSingleTon::m_pInstance) //内部类不能去访问包含其类的非公有成员变量//delete CSingleTon::m_pInstance;if(CSingleTon::GetInstance())delete CSingleTon::GetInstance();}};static CGarbo Garbo;//定义一静态成员,在程序结束时,系统会调用它的析构函数protected:int m_num;public:static CSingleTon* GetInstance(); //用来获取实例void SetNum(int num); //设置m_num的值int GetNum(); //获取m_num的值void PrintNum(); //在控制台上打印m_num的值};
Singleton.cpp#include "singleton.h"#include <iostream>using namespace std;CSingleTon *CSingleTon::m_pInstance = CSingleTon::GetInstance();//静态成员变量的初始化CSingleTon::CSingleTon(){cout<<"Construct"<<endl;this->m_num = 0;}CSingleTon::~CSingleTon(){cout<<"Destruct"<<endl;if(m_pInstance != NULL)delete m_pInstance;}CSingleTon* CSingleTon::GetInstance(){if(m_pInstance == NULL){m_pInstance = new CSingleTon();}return m_pInstance;}void CSingleTon::SetNum(int num){this->m_num = num;}int CSingleTon::GetNum(){return this->m_num;}void CSingleTon::PrintNum(){cout<<this->m_num<<endl;}
Main.cpp#include <iostream>using namespace std;#include "singleton.h"int main(void){CSingleTon *tonfir = CSingleTon::GetInstance();CSingleTon *tonsec = CSingleTon::GetInstance();tonfir->PrintNum();tonsec->PrintNum();tonfir->SetNum(5);tonsec->PrintNum();return 0;}
原理:
程序运行结束时,系统自动析构所有的全局变量。也会析构所有类的静态成员变量。
在程序运行结束时,系统会调用CSingleTon的静态成员Garbo的析构函数,该析构函数会删除单例的唯一实例。
使用这种方法释放单例对象有以下特征:
1.在单例类内部定义专有的嵌套类
2.在单例类内部定义私有的专门用于释放单例对象的静态成员
3.利用程序在结束时,析构静态变量的特性,选择最终的释放时机
4.使用C++单例模式的代码不需要任何操作,不必关心对象的释放
- 单例、单例模式
- 单例模式-多线程单例模式
- 单件模式(单例模式)
- 设计模式------单例模式
- 设计模式------单例模式
- 设计模式-单例模式
- 设计模式 - 单例模式
- 设计模式---单例模式
- 设计模式---单例模式
- PHP模式-单例模式
- 【设计模式】单例模式
- 设计模式-单例模式
- 设计模式----单例模式
- 设计模式--单例模式
- 设计模式-单例模式
- 单例模式(单子模式)
- 设计模式-单例模式
- [设计模式] 单例模式
- 匿名内部类
- HTTP常见错误总结
- 程序员的路
- 快速定位内存泄漏之处
- shell脚本分割文件成相同行数的文件
- 单例模式
- Nutch插件机制分析
- android 自定义listener对象被自动析构和重建
- websevice
- oracle 例程
- 再谈“我是怎么招骋程序员的”
- CTreeCtrl用法 CTreeCtrl使用详解 .
- ExtUtils::MakeMaker
- what is difference between IRQ and FRQ