因為類的靜態成員變量是所有實例共用的.所以得在類外初始化.
調用的時候可以通過對象調用,也可以通過類直接調用
class?A
{
public:
????int?i;????//有默認值
};
class?B
{
public:
????static?int?n;
????static?A?Aobj;
};
int?B::n?=?1;????//靜態成員變量的初始化
A?B::Aobj;???????//靜態成員變量的初始化(實例化)
void?main()
{
??? B Bobj; ?//注釋掉這行也能輸出B::n
????printf("B::n=%d ?Bobj.n=%d ?Bobj.Aobj.i=%d\n",?B::n,?Bobj.n,?Bobj.Aobj.i);
}
{
public:
????int?i;????//有默認值
};
class?B
{
public:
????static?int?n;
????static?A?Aobj;
};
int?B::n?=?1;????//靜態成員變量的初始化
A?B::Aobj;???????//靜態成員變量的初始化(實例化)
void?main()
{
??? B Bobj; ?//注釋掉這行也能輸出B::n
????printf("B::n=%d ?Bobj.n=%d ?Bobj.Aobj.i=%d\n",?B::n,?Bobj.n,?Bobj.Aobj.i);
}
?輸出“B::n=1 Bobj.n=1 Bobj.Aobj.i=0 ”
?
私有的靜態成員變量也是放在類外初始化的.這看起來跟它的私有屬性不相符.
再做下面的測試,發現了一個有趣的現象.
class?B
{
{
private:
????static?int?i;
public:
????B(){i=3;};????//把這行注釋掉,輸出變成2
????int?p(){return?i;};
};
int?B::i?=?2;??????//把這行注釋掉,編譯報錯
void?main()
{
????B?Bobj;
????printf("private:?static?int?B::i=%d\n",?Bobj.p());????//輸出3
}
????static?int?i;
public:
????B(){i=3;};????//把這行注釋掉,輸出變成2
????int?p(){return?i;};
};
int?B::i?=?2;??????//把這行注釋掉,編譯報錯
void?main()
{
????B?Bobj;
????printf("private:?static?int?B::i=%d\n",?Bobj.p());????//輸出3
}
類外的初始化那一行是必要的,而且是在構造函數之前就執行了的
最重要的一點,如果靜態成員變量不初始化,編譯會報錯.
我們知道C++類的靜態成員變量是需要初始化的,但為什么要初始化呢。
其實這句話“靜態成員變量是需要初始化的”是有一定問題的,應該說“靜態成員變量需要定義”才是準確的,而不是初始化。
兩者的區別在于:初始化是賦一個初始值,而定義是分配內存。
靜態成員變量在類中僅僅是聲明,沒有定義,所以要在類的外面定義,實際上是給靜態成員變量分配內存。
可通過以下幾個例子更形象的說明這個問題:
//test.cpp
#include <stdio.h>
class A {
public: static int a; //聲明但未定義
};
int main() { printf("%d", A::a);return 0;
}
編譯以上代碼會出現“對‘A::a’未定義的引用”錯誤。這是因為靜態成員變量a未定義,也就是還沒有分配內存,顯然是不可以訪問的。
再看如下例子:
//test.cpp
#include <stdio.h>
class A {
public: static int a; //聲明但未定義
};
int A::a = 3; //定義了靜態成員變量,同時初始化。也可以寫"int A:a;",即不給初值,同樣可以通過編譯,這時a默認為0
int main() { printf("%d", A::a);return 0;
}
這樣就對了,因為給a分配了內存,所以可以訪問靜態成員變量a了。
因為類中的靜態成員變量僅僅是聲明,暫時不需分配內存,所以我們甚至可以這樣寫代碼:
//a.cpp
class B; //這里我們使用前置聲明,完全不知道B是什么樣子
class A {
public:static B bb;//聲明了一個類型為B的靜態成員,在這里編譯器并未給bb分配內存。//因為僅僅是聲明bb,所以編譯器并不需要知道B是什么樣子以及要給其對應的對象分配多大的空間。//所以使用前置聲明"class B"就可以保證編譯通過。
};