C++之構(gòu)造函數(shù)(Constructors)和static
構(gòu)造函數(shù)和靜態(tài)成員:必須顯式定義靜態(tài)成員變量,不能出現(xiàn)在構(gòu)造的初始化列表中
"undefined external" 的鏈接錯誤。
靜態(tài)變量初始化順序產(chǎn)生的錯誤是難以覺察,因為它發(fā)生在mian之前,如果你有兩個靜態(tài)成員x,y,分別位于兩個文件x.cpp、y.cpp中,而y在初始化要調(diào)用x,這樣的場景很常見,出錯的幾率有百分之五十。如果先初始化x,一切OK,如果先初始化y,那就慘了。例如:
在這里有個static initialization和static deinitialization,前者意義大家都知道,后者則是去初始化指的是在應用之前被別的代碼給析構(gòu)了,導致我們用的這個靜態(tài)量沒有初始化,這個是很致命的,尤其在靜態(tài)指針中,表現(xiàn)的更為明顯。
當然static這個關(guān)鍵字也并非一無是處,下面的代碼中的錯誤就可以用staic來解決:
1 class Fred {
2 public:
3 Fred();
4
5 private:
6 int i_;
7 static int j_;
8 };
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;
通常把靜態(tài)成員的聲明放到.H文件,定義放到.cpp中。如果沒有定義,會出現(xiàn) : 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;
靜態(tài)變量初始化順序產(chǎn)生的錯誤是難以覺察,因為它發(fā)生在mian之前,如果你有兩個靜態(tài)成員x,y,分別位于兩個文件x.cpp、y.cpp中,而y在初始化要調(diào)用x,這樣的場景很常見,出錯的幾率有百分之五十。如果先初始化x,一切OK,如果先初始化y,那就慘了。例如:
1 // File x.cpp
2 #include "Fred.h"
3 Fred x;
4
2 #include "Fred.h"
3 Fred x;
4
1 // File y.cpp
2 #include "Barney.h"
3 Barney y;
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 }
解決這種靜態(tài)成員初始化的方法很多,一個簡單的方法就是用靜態(tài)方法x()替代Fred x,然后返回這個Fred的引用,如下所示:2 #include "Barney.h"
3
4 Barney::Barney()
5 {
6

7 x.goBowling();
8

9 }
1 // File x.cpp
2
3 #include "Fred.h"
4
5 Fred& x()
6 {
7 static Fred* ans = new Fred();
8 return *ans;
9 }
這個靜態(tài)變量這初始化一次,以后將一直返回同樣的Fred對象。這是修改后的代碼2
3 #include "Fred.h"
4
5 Fred& x()
6 {
7 static Fred* ans = new Fred();
8 return *ans;
9 }
1 // File Barney.cpp
2 #include "Barney.h"
3
4 Barney::Barney()
5 {
6
7 x().goBowling();
8
9 }
第一次使用,F(xiàn)red對象先被構(gòu)造。但是這個解決方法使用時要慎重,在這里第一選擇是使用靜態(tài)成員,使用靜態(tài)指針會有一些副作用,倒不是擔心內(nèi)存泄露,在程序退出時系統(tǒng)會自己釋放這些堆空間。在使用靜態(tài)變量時要保證第一次使用前被初始化,最后一次使用后被析構(gòu),在這里我們要注意的是析構(gòu)函數(shù)的代碼。如果靜態(tài)變量a、b、c在構(gòu)造時調(diào)用ans沒問題,但是在析構(gòu)時如果還調(diào)用ans,程序極有可能崩潰。這種應用在實際中并不多見,解決的方法有三種,待以后的主題中在講。2 #include "Barney.h"
3
4 Barney::Barney()
5 {
6

7 x().goBowling();
8

9 }
在這里有個static initialization和static deinitialization,前者意義大家都知道,后者則是去初始化指的是在應用之前被別的代碼給析構(gòu)了,導致我們用的這個靜態(tài)量沒有初始化,這個是很致命的,尤其在靜態(tài)指針中,表現(xiàn)的更為明顯。
當然static這個關(guān)鍵字也并非一無是處,下面的代碼中的錯誤就可以用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改變了初始化的順序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 }
但是上面的更改只限于編譯器的內(nèi)置數(shù)據(jù)類型,而不是用戶自定義的數(shù)據(jù)類型。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 }
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 }
posted on 2010-05-08 22:27 Benjamin 閱讀(1485) 評論(0) 編輯 收藏 引用 所屬分類: C/C++