靜態成員變量的初始化


我們定義如下類:


複製代碼

//A.h
class A
{
private:
static const int m = 5;
static int n;
static vector<int> buf;
};

複製代碼

其中包含三個私有的靜態類成員,C++規定const靜態類成員可以直接初始化,其他非const的靜態類成員需要在類聲明以外初始化,我們一般選擇在類的實現文件中初始化,初始化的方式是書寫一遍類型的定義:



//A.cpp
int A::n; //不指定任何初始值,系統自動初始化爲0
vector<int> A::buf; //調用vector的默認構造函數來初始化
//注意:調用默認構造函數時,不要使用括號,否則編譯器將把A::buf()當做靜態成員函數,
//但是A::buf()實際沒有被聲明,所以編譯器將報錯

或者:


//A.cpp
int A::n(9); //使用字面量9來初始化n
vector<int> A::buf(100); //調用vector的帶參構造函數來初始化




對於更復雜的情形 ,如沒有構造函數可以調用(比如單例模式實現的類),或者需要多步驟才能完成的初始化怎麼辦?
假設有一個類S實現了單例模式,S的實例是通過調用S的靜態方法S::GetInstance()來獲得的,現在定義一個包含S作爲靜態成員的類:



//B.h
class B
{
private:
static S s;
};

按照前面的介紹,我們或許應該以下面這種方式初始化s:


//B.cpp
#include <B.h>
S B::s; //編譯器會報錯,因爲S沒有可以調用的構造函數

解決方法是定義一個靜態方法,負責初始化靜態成員s:


複製代碼

//B.h
class B
{
public:
static S Init();
private:
static S s;
};

//B.cpp
#include <B.h>
S B::Init()
{
....
return S::Instance();
}
S B::s = B::Init(); //調用靜態函數初始化靜態成員

複製代碼



上例中,爲了初始化類B的靜態 成員s,我們定義了一個公有的靜態方法Init(),它可以很好的工作。但是,在現實的工程中,我們很可能碰到更進一步的要求,就是希望Init()僅僅作爲靜態變量s的初始化器使用,而不能使用在程序中別的地方,但是我們又不能把Init()聲明爲private,這樣Init()就不能被調用來初始化s了。解決的方法是使用內部類:


//B.h
class B
{
private:
class C
{
public:
static S InitB();
};
static S s;
};

//B.cpp
S B::C::InitB()
{
....
return S::Instance();
}
S B::s = B::C::InitB(); //調用內部類的靜態成員函數來初始化靜態數據成員




因爲C是B的內部類,C僅在B的作用域範圍內可見,如果程序的其他地方調用了B::C::InitB(),編譯器將報錯,因爲C不可訪問。



最後說一下,從初始化的方式可以看出來,類的靜態數據成員其實就是“帶類名”的全局變量。

靜態數據成員必須顯式初始化,否則在類方法中操作該成員時,將報鏈接錯誤 undefined reference to `A::buf' (gcc中)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章