static小結
static的引入
static 是C++中非經常常使用的修飾符,它被用來控制變量的存儲方式和可見性。
函數內部定義的變量,在程序運行到它的定義處時,編譯器為它在棧上分配空間,函數在棧上分配的空間在此函數運行結束時會釋放掉,這樣就產生了一個問題:假設想將函數中此變量的值保存至下一次調用時。怎樣實現? 最easy想到的方法是定義一個全局的變量。但定義為一個全局變量有很多缺點,最明顯的缺點是破壞了此變量的訪問范圍(使得在此函數中定義的變量。不只受此函數控制)。而static變量能夠保持該變量的值,使得函數在下次調用時還保持上次函數退出時的值。
static內部機制
static被引入以告知編譯器。將變量存儲在程序的靜態存儲區而非棧上空間,靜態數據成員按定義出現的先后順序依次初始化。注意靜態成員嵌套時,要保證所嵌套的成員已經初始化了。
static的優勢:
能夠節省內存。由於它是全部對象所公有的,因此,對多個對象來說。靜態數據成員僅僅存儲一處,供全部對象共用。靜態數據成員的值對每一個對象都是一樣,但它的值是能夠更新的。僅僅要對靜態數據成員的值更新一次,保證全部對象存取更新后的同樣的值,這樣能夠提高時間效率。
static類成員
類的對象構建過程不會動到static變量和函數,由於它存在靜態內存。程序載入進內存的時候它就存在。而對象生命周期不同。
static數據成員
static數據成員要在程序一開始執行時就必須存在。由於函數在程序執行中被調用,所以靜態數據成員不能在不論什么函數內分配空間和初始化。
static數據成員要實際地分配空間。故不能在類的聲明中定義(僅僅能聲明數據成員),也不能在頭文件里類聲明的外部定義,由於那會造成在多個使用該類的源文件里,對其反復定義。
static數據成員必須在類定義體的外部定義(正好一次)。
不像普通數據成員,static成員不是通過類構造函數進行初始化。而是應該在定義時進行初始化。
- 在類中,靜態成員能夠實現多個對象之間的數據共享,而且使用靜態數據成員還不會破壞隱藏的原則。即保證了安全性。因此,靜態成員是類的全部對象中共享的成員。而不是某個對象的成員。
- 靜態數據成員能夠節省內存,由於它是全部對象所公有的。因此,對多個對象來說,靜態數據成員僅僅存儲一處。供全部對象共用。靜態數據成員的值對每一個對象都是一樣。但它的值是能夠更新的。僅僅要對靜態數據成員的值更新一次,保證全部對象存取更新后的同樣的值,這樣能夠提高時間效率。
- 初始化格式為 <數據類型><類名>::<靜態數據成員名>=<值> 。初始化在類體外進行,而前面不加static,以免與一般靜態變量或對象相混淆。
static成員函數
- 在靜態成員函數的實現中不能直接引用類中說明的非靜態成員。能夠引用類中說明的靜態成員。
假設靜態成員函數中要引用非靜態成員時。可通過對象來引用。
- 靜態成員函數,不屬於不論什么一個詳細的對象,那么在類的詳細對象聲明之前就已經有了內存區,而非靜態數據成員還沒有分配內存空間。那么在靜態成員函數中使用非靜態成員函數,就好像沒有聲明一個變量卻提前使用它一樣。
- static成員函數沒有this指針,不能被聲明為const。不能被聲明為虛函數。
單例模式(Singleton)
介紹
單例(Singleton)模式是保證一個類僅有一個實例,並提供一個訪問它的全局訪問點。
有非常多地方須要這種功能模塊。如系統的日志輸出,GUI應用必須是單鼠標,MODEM的聯接須要一條且僅僅須要一條電話線,操作系統僅僅能有一個窗體管理器,一台PC連一個鍵盤。
Singleton模式讓類自身負責保存它的唯一實例。這個類能夠保證沒有其它實例能夠被創建(通過截取創建新對象的請求)。而且它能夠提供一個訪問該實例的方法。
適用性
- 當類僅僅能有一個實例並且客戶能夠從一個眾所周知的訪問點訪問它時。
- 當這個唯一實例應該是通過子類化可擴展的。並且客戶應該無需更改代碼就能使用一個
擴展的實例時。
結構

實現
保證一個唯一的實例
將創建唯一實例的操作隱藏在一個類操作(即一個靜態成員函數)后面,由它保證僅僅有一個實例被創建。
這個操作能夠訪問保存唯一實例的變量。並且它能夠保證這個變量在返回值之前用這個唯一實例初始化。
在C++中,你能夠用Singleton類的靜態成員函數Instance來定義這個類操作。Singleton還定義一個靜態成員變量_instance,它包括了一個指向它的唯一實例的指針。
Singleton類定義:
class Singleton{
public:
static Singleton* Instance();
protected:
Singleton();
//構造函數為protected,當試圖直接實例化Singleton類時。會得到編譯時的錯誤信息
//保證僅有一個實例能夠被創建
private:
static Singleton* _instance;
};
Singleton* Singleton::_instance = 0;
Singleton* Singleton::Instance() {
if(_instance == 0){
_instance = new Singleton;
}
return _instance;
}
釋放Singleton對象
單例類Singleton有下面特征:
它有一個指向唯一實例的靜態指針_pInstance,而且是私有的;
它有一個公有的函數。能夠獲取這個唯一的實例。而且在須要的時候創建該實例;
它的構造函數是私有的,這樣就不能從別處創建該類的實例。
我們須要一種方法,正常的刪除該實例
一個妥善的方法是讓這個類自己知道在合適的時候把自己刪除,或者說把刪除自己的操作掛在操作系統中的某個合適的點上,使其在恰當的時候被自己主動運行。
程序在結束的時候,系統會自己主動析構全部的全局變量。其實,系統也會析構全部的類的靜態成員變量,就像這些靜態成員也是全局變量一樣。利用這個特征。我們能夠在單例類中定義一個這種靜態成員變量,而它的唯一工作就是在析構函數中刪除單例類的實例。
class CSingleton
{
private:
CSingleton()
{
}
static CSingleton *m_pInstance;
class CGarbo //它的唯一工作就是在析構函數中刪除CSingleton的實例
{
public:
~CGarbo()
{
if(CSingleton::m_pInstance)
delete CSingleton::m_pInstance;
}
};
static CGarbo Garbo; //定義一個靜態成員變量,程序結束時。系統會自己主動調用它的析構函數
public:
static CSingleton * GetInstance()
{
if(m_pInstance == NULL) //推斷是否第一次調用
m_pInstance = new CSingleton();
return m_pInstance;
}
};
類CGarbo被定義為CSingleton的私有內嵌類,以防該類被在其它地方濫用。
程序執行結束時,系統會調用CSingleton的靜態成員Garbo的析構函數,該析構函數會刪除單例的唯一實例。
使用這樣的方法釋放單例對象有下面特征:
在單例類內部定義專有的嵌套類;
在單例類內定義私有的專門用於釋放的靜態成員。
利用程序在結束時析構全局變量的特性,選擇終於的釋放時機。
使用單例的代碼不須要不論什么操作,不必關心對象的釋放。
創建Singleton類的子類(單件注冊表方法)
使用單件注冊表(registry of singleton),使得singleton類能夠依據名字在一個眾所周知的注冊表中注冊它們的單件實例。
這個注冊表在字符串名字和單件之間建立映射。當Instance須要一個單件時,它參考注冊表,依據名字請求單件。
class Singleton{
public:
static void Register(const char* name, Singleton *);
static Singleton* Instance();
protected:
static Singleton* Lookup(const char* name);
private:
static Singleton* _instance;
static List<NameSingletonPair>* _registry;
};
Register以給定的名字注冊Singleton實例。為保證注冊簡單。我們將它存儲一列NameSingletonPair對象。 每一個NameSingletonPair將一個名字映射到一個單件。Lookup操作依據給定單件的名字進行查找。
Singleton* Singleton::Instance(){
if(_instance == 0){
const char* singletonName = getenv("SINGLETON");
//environment supplies this at startup
_instance = Lookup(singletonName);
//Lookup returns 0 if there's no such singleton
}
return _instance;
}
Singleton類能夠在構造函數中來注冊自己。
MySingleton::MySingleton() {
Sinleton::Register("MySingleton",this);
}
由此。Singleton類不再負責創建單件。它的主要職責是使得供選擇的單件對象在系統中能夠被訪問。