構造函數和靜態成員:必須顯式定義靜態成員變量,不能出現在構造的初始化列表中
1 class Fred {
2 public:
3 Fred();
4 
5 private:
6 int i_;
7 static int j_;
8 };
Fred::Fred()
: i_(10) // OK: you can (and should) initialize member data this way
, j_(42) // Error: you cannot initialize static member data like this
{

}
// You must define static data members this way:
int Fred::j_ = 42;
通常把靜態成員的聲明放到.H文件,定義放到.cpp中。如果沒有定義,會出現
"undefined external" 的鏈接錯誤。
靜態變量初始化順序產生的錯誤是難以覺察,因為它發生在mian之前,如果你有兩個靜態成員x,y,分別位于兩個文件x.cpp、y.cpp中,而y在初始化要調用x,這樣的場景很常見,出錯的幾率有百分之五十。如果先初始化x,一切OK,如果先初始化y,那就慘了。例如:
1 // File x.cpp
2 #include "Fred.h"
3 Fred x;
4
1 // File y.cpp
2 #include "Barney.h"
3 Barney y;
1 // File Barney.cpp
2 #include "Barney.h"
3
4 Barney::Barney()
5 {
6 
7 x.goBowling();
8 
9 }
解決這種靜態成員初始化的方法很多,一個簡單的方法就是用靜態方法x()替代Fred x,然后返回這個Fred的引用,如下所示:
1 // File x.cpp
2
3 #include "Fred.h"
4
5 Fred& x()
6 {
7 static Fred* ans = new Fred();
8 return *ans;
9 }
這個靜態變量這初始化一次,以后將一直返回同樣的Fred對象。這是修改后的代碼
1 // File Barney.cpp
2 #include "Barney.h"
3
4 Barney::Barney()
5 {
6 
7 x().goBowling();
8 
9 }
第一次使用,Fred對象先被構造。但是這個解決方法使用時要慎重,在這里第一選擇是使用靜態成員,使用靜態指針會有一些副作用,倒不是擔心內存泄露,在程序退出時系統會自己釋放這些堆空間。在使用靜態變量時要保證第一次使用前被初始化,最后一次使用后被析構,在這里我們要注意的是析構函數的代碼。如果靜態變量a、b、c在構造時調用ans沒問題,但是在析構時如果還調用ans,程序極有可能崩潰。這種應用在實際中并不多見,解決的方法有三種,待以后的主題中在講。
在這里有個static initialization和static deinitialization,前者意義大家都知道,后者則是去初始化指的是在應用之前被別的代碼給析構了,導致我們用的這個靜態量沒有初始化,這個是很致命的,尤其在靜態指針中,表現的更為明顯。
當然static這個關鍵字也并非一無是處,下面的代碼中的錯誤就可以用staic來解決:
1 #include <iostream>
2
3 int f(); // forward declaration
4 int g(); // forward declaration
5
6 int x = f();
7 int y = g();
8
9 int f()
10 {
11 std::cout << "using 'y' (which is " << y << ")\n";
12 return 3*y + 7;
13 }
14
15 int g()
16 {
17 std::cout << "initializing 'y'\n";
18 return 5;
19 }
這段代碼顯然不能通過編譯,下面通過static改變了初始化的順序
1 #include <iostream>
2
3 int f(); // forward declaration
4 int g(); // forward declaration
5
6 int x = f();
7 int y = g();
8
9 int f()
10 {
11 std::cout << "using 'y' (which is " << y << ")\n";
12 return 3*y + 7;
13 }
14
15 int g()
16 {
17 std::cout << "initializing 'y'\n";
18 return 5;
19 }
1 #include <iostream>
2
3 int f(); // forward declaration
4 int g(); // forward declaration
5
6 int x = f();
7 int y = g();
8
9 int f()
10 {
11 std::cout << "using 'y' (which is " << y << ")\n";
12 return 3*y + 7;
13 }
14
15 int g()
16 {
17 std::cout << "initializing 'y'\n";
18 return 5;
19 }
但是上面的更改只限于編譯器的內置數據類型,而不是用戶自定義的數據類型。