轉錄至https://www.inside.com.tw/2015/01/13/coder-hacker-and-architect
在C++中,static有很多不同的意思,打字猴也常遇到static相關的問題(多半是名詞解釋),所以在這篇文章中做一個整理:
1. static修飾local variables
表示該local variable的lifetime和整個程式一樣長,但是scope卻只在該function裡面。
打字猴曾遇到的問題如下,請問這段程式執行後的印出結果:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
#include <iostream> using namespace std; void Foo() { static int a = 0; cout << a; ++a; } void main() { for ( int i = 0; i < 5; ++i) { Foo(); } } |
印出的結果為:01234
2. static修飾global variables
表示該global variable的scope被限制在該translation unit中,無法從其他translation unit中access到該global variable。
我們來看一個例子:
===== In a.cpp =====
1
|
int g_a = 566; //external linkage by default |
===== In b.cpp =====
1
2
3
4
5
6
7
|
#include <iostream> using namespace std; void main() { extern int g_a; cout << g_a; } |
宣告在a.cpp的變數g_a是external linkage by default,所以打字猴可以在b.cpp中透過extern關鍵字來access到它,以上範例會印出566。
但是如果我們把上面範例的g_a用static來修飾:
===== In a.cpp =====
1
|
static int g_a = 566; //external linkage by default |
===== In b.cpp =====
1
2
3
4
5
6
7
|
#include <iostream> using namespace std; void main() { extern int g_a; cout << g_a; } |
在編譯時就會發生以下Error (with VS 2013 Express)
Source.obj : error LNK2001: unresolved external symbol “int g_a” (?g_a@@3HA)
因為我們已經限制了g_a的scope,無法在另一個translation unit中access到它。
3. static修飾global functions
同global variables。
但打字猴要提醒的是,在C++ standard中建議以unnamed namespace來取代static global variable/function,我們會在另一篇文章中討論這件事。
4. static修飾class fields
表示該static class field的lifetime整個程式一樣長,其scope則是看它的access level;每個class的instance會共用同一個static class field的instance。
我們來看一個例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
#include <iostream> using namespace std; class CFoo { public : void Bar() { cout << _data << endl; } static void Bear() { cout << _data << endl; } void Fuzzy( int d) { _data = d; } private : static int _data; }; int CFoo::_data = 183; void main() { CFoo f1; f1.Bar(); f1.Bear(); CFoo f2; f2.Fuzzy(5566); f1.Bar(); f1.Bear(); } |
以上範例的結果會印出:
183
183
5566
5566
我們可以發現,non-static method和static method都可以access到打字猴定義的static int _data。而f1和f2這2個不同的instance共用同一個static int _data。另外值得一提的是,我們在class的外面來初始化int CFoo::_data = 183;,static class member的初始化請看這篇文章。
5. static修飾class methods
表示該static class method沒有implicit this argument(表示它不能access non-static class member);不用class instance就可以invoke它。但是static class method有class的scope(取決於它的access level)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
#include <iostream> using namespace std; class CFoo { public : CFoo( int d) : m_data(d) {} static void Bar() { cout << "Bar" << endl; } private : int m_data; }; void main() { CFoo::Bar(); } |
在上面範例中可以發現,打字猴不用CFoo的instance就可以呼叫Bar()。
1
2
3
4
5
6
7
8
9
10
|
#include <iostream> using namespace std; class CFoo { public : CFoo( int d) : m_data(d) {} static void Bear() { cout << m_data << endl; } private : int m_data; }; |
當打字猴打算在static class method Bear()中access m_data時,會出現以下compile error
error C2597: illegal reference to non-static member ‘CFoo::m_data’
我們可以發現static關鍵字在修飾不同東西時,會代表不同的意思。這也是C++ standard中建議以unnamed namespace來取代static global variable/function的原因之一。
最後值得一提的是,static global variable和static local variable如果沒有給初值的話,compiler會自動給0當初值;但是如果是一般的local variable沒有給初值的話,不同的compiler會有不同的behavior。(但是best practice還是在init時要給初值,避免程式的執行不如預期,也可以增加可讀性。)
1
2
3
4
5
6
7
8
9
|
static int g_var; void main() { static int s_var; cout << g_var << endl; cout << s_var << endl; } |
以上程式執行的結果為:
0
0