C++ 單例類别範本(詳解)

weixin_42660691發表於2020-12-15

單例類

描述

指在整個系統生命期中,一個類最多隻能有一個例項(instance)存在,使得該例項的唯一性(例項是指一個物件指標) , 比如:統計線上人數

在單例類裡,又分為了懶漢式和餓漢式,它們的區別在於建立例項的時間不同:

懶漢式 : 指程式碼執行後,例項並不存在,只有當需要時,才去建立例項(適用於單執行緒)
餓漢式 : 指程式碼一執行,例項已經存在,當時需要時,直接去呼叫即可(適用於多執行緒)

用法

將建構函式的訪問屬性設定為private,
提供一個GetInstance()靜態成員函式,只能供使用者訪問唯一一個例項.
定義一個靜態成員指標,用來供使用者獲取
過載 (=)賦值操作符以及拷貝建構函式,並設為private, 避免物件間拷貝,複製.

初探單例類-懶漢式:

複製程式碼
#include
using namespace std;

class CSingleton
{
private:
static CSingleton* m_pInstance;

   CSingleton()         //建構函式為private
   {
   } 

   CSingleton& operator = (const CSingleton& t);
   CSingleton(const CSingleton &);

public:
static CSingleton* getInstance()
{
if(m_pInstance==NULL)
m_pInstance= new CSingleton();

           return m_pInstance;
   }

   void print()
   {
       cout<<this<<endl;      
   }

};

CSingleton* CSingleton::m_pInstance = NULL;

int main()
{
CSingleton *p1=CSingleton::getInstance();
CSingleton *p2=CSingleton::getInstance();
CSingleton *p3=CSingleton::getInstance();

   p1->print();
   p2->print();
   p3->print();

return 0;
}
複製程式碼
執行列印:

0x6e2d18
0x6e2d18
0x6e2d18
從列印結果可以看出,該指標物件指向的都是同一個地址,實現了一個類最多隻能有一個例項(instance)存在.

注意:由於例項(instance),在系統生命期中,都是存在的,所以只要系統還在執行,就不需要delete

上面的懶漢式如果在多執行緒情況下 ,多個Csingleton指標物件同時呼叫getInstance()成員函式時,由於m_pInstance = NULL,就會建立多個例項出來.(除非使用mutex來新增互斥)

所以,在多執行緒情況下,需要使用餓漢實現

程式碼如下:

複製程式碼
class CSingleton
{
private:

   static CSingleton* m_pInstance;

    CSingleton()         //建構函式為private
   {
   }             

   CSingleton& operator = (const CSingleton& t);
   CSingleton(const CSingleton &); 

public:
static CSingleton* getInstance()
{
return m_pInstance;
}
};

CSingleton* CSingleton::m_pInstance = new CSingleton;
複製程式碼
也可以直接粗暴的用static變數:

複製程式碼
class CSingleton
{
private:

    CSingleton()         //建構函式為private
   {
   }             

   CSingleton& operator = (const CSingleton& t);
   CSingleton(const CSingleton &); 

public:
static CSingleton* getInstance()
{
static CSingleton Instance;
return &Instance;
}
};
複製程式碼
注意:

類函式中如果使用static靜態區域性變數,那麼該變數是不安全的,因為static變數是一直存在的,所有物件都會共享這個變數.

單例類别範本

我們現在講解的僅僅是個框架,裡面什麼都沒有,不能滿足需求啊,所以還要寫為單例類别範本標頭檔案,當需要單例類時,直接宣告單例類别範本標頭檔案即可

寫CSingleton.h

複製程式碼
#ifndef SINGLETON_H
#define SINGLETON_H

template
class CSingleton
{
private:
static T* m_pInstance;

    CSingleton()         //建構函式為private
    {     

}

public:
static T* getInstance()
{
return m_pInstance;
}
};

template
T* CSingleton :: m_pInstance = new T;

#endif
複製程式碼
當我們需要這個單例類别範本時,只需要在自己類裡通過friend新增為友元即可,

接下來試驗單例類别範本

寫main.cpp

複製程式碼
#include
#include
#include “CSingleton.h”

using namespace std;

class Test
{
friend class CSingleton ; //宣告Test的友元為單例類别範本
private:
string mstr;

    Test(): mstr("abc")
   {
   }

   Test& operator = (const Test& t);
   Test(const Test&);

public:
void Setmstr(string t)
    {
mstr=t;
    }

    void print()
   {
    cout<<"mstr = "<<mstr<<endl;
    cout<<"this = "<<this<<endl;
   }

};

int main()
{
Test *pt1 = CSingleton::getInstance();
Test *pt2 = CSingleton::getInstance();

    pt1->print();
    pt2->print();

    pt1->Setmstr("ABCDEFG");
    pt2->print();

    return 0;

}
複製程式碼
執行列印:

複製程式碼
mstr = abc
this = 0x2d2e30

mstr = abc
this = 0x2d2e30

mstr = ABCDEFG
this = 0x2d2e30
複製程式碼

相關文章