1. static variable 靜態變數
static 關鍵字放在變數前面時,代表這個變數的存活時間和整個程式一樣長,而作用域(scope)則維持不變。
(說明:作用域(scope):變數在程式中可以被存取的範圍)
來看看範例吧
void TestFunction(int i, int nEnd)
{
static int x = 0;
int y = 0;
x++;
y++;
if(i == (nEnd-1))
{
cout<<"x="<<x<<endl;
cout<<"y="<<y<<endl;
}
}
int main()
{
for(int i = 0 ; i < 5 ; i++)
TestFunction(i, 5);
system("pause");
return 0;
}
x=5 y=1 |
TestFunction 函式會對 x , y 配置記憶體空間並進行初始化,當 TestFunction 函式結束的時候,會將 y 的記憶體歸還,下次呼叫時再重新配置一次;而 x 被宣告成 static,所以 x 的記憶體不會歸還,沿用著上次的值。
小提醒1:可以理解為被宣告成 static 的變數,就類似於全域變數了,只是因為 x 是宣告在 TestFunction 函式裡,所以只能在 TestFunction 函式裡使用。所以如果把 x 宣告在外面當成真正的全域變數,執行結果是一樣的。
int x = 0;
void TestFunction(int i, int nEnd)
{
//static int x = 0;
int y = 0;
x++;
y++;
if (i == (nEnd - 1))
{
cout << "x=" << x << endl;
cout << "y=" << y << endl;
}
}
x=5 y=1 |
小提醒2:在 TestFunction 函式裡,static int x=0; 的初始化只會做一次。如果寫成 static int x; x=0; 那結果就會跟 y 一樣是 1。考試的時候很容易成為陷阱,一定要小心。
void TestFunction(int i, int nEnd)
{
static int x;
x = 0;
int y = 0;
x++;
y++;
if (i == (nEnd - 1))
{
cout << "x=" << x << endl;
cout << "y=" << y << endl;
}
}
x=1 y=1 |
2. static member variable 靜態成員變數
class A
{
public:
static int m_nNum;//宣告 static member variable
};
//必須定義在外面,不寫不行
int A::m_nNum = 0;
int main()
{
cout<<A::m_nNum<<endl;//不需要產生物件就可以使用
system("pause");
return 0;
}
在 class 裡把成員變數宣告成 static,代表它是「與 class 相關連」,而不是「與物件相關連」的變數。它獨立配置記憶體,獨立於 class 的任何物件而存在,這個 class 產生的所有物件共用同一個靜態成員變數,甚至不需要有物件也能夠被使用。
因為靜態成員變數不屬於任何物件,所以必須定義在外面。與一般成員變數不同,靜態成員變數並不是經由建構子初始化,而是在定義時被初始化。
小提醒3:可以把靜態成員變數理解為是一個只存在於某個 class 裡的全域變數。
3. static member function 靜態成員函式
如果靜態成員變數是 private 的
class A
{
private: //改成 private
static int m_nNum;//宣告 static member variable
};
int A::m_nNum = 0;
int main()
{
cout<<A::m_num<<endl;//不能用,因為 m_nNum 是 private 的
system("pause");
return 0;
}
如果靜態成員變數是 private 的,那就沒有辦法直接取值 了,那該怎麼辦呢?寫一個 Get 的成員函式嗎?
class A
{
private:
static int m_nNum;//宣告 static member variable
public:
int GetNum(){ return m_nNum; }
};
int A::m_nNum = 0;
int main()
{
A a1;
cout<<a1.GetNum()<<endl;
system("pause");
return 0;
}
是可以用啦,可是這樣不是很奇怪嗎?因為 m_nNum 在不是 private 的時候,可以不用產生物件就可以存取,但是用 Get member function 卻要產生一個物件才能用。所以這樣的方法並不適合,因此,就要把 Get member function 也宣告成 static 的。
class A
{
private:
static int m_nNum;//宣告 static member variable
public:
static int GetNum(){ return m_nNum; }//宣告 static member function
};
int A::m_nNum = 0;
int main()
{
//沒有產生物件也可使用
cout<<A::GetNum()<<endl;
system("pause");
return 0;
}
在 class 裡把成員函式宣告成 static,代表它是「與 class 相關連」,而不是「與物件相關連」的成員函式。它獨立於任何物件存在,這個 class 產生的所有物件使用同一個靜態成員函式,甚至不需要有物件也能夠被呼叫。
所以它不能使用 this,也不能存取 class 裡的一般成員變數,當然也不能使用一般成員函式了。也就是說,靜態成員函式 只能存取 靜態成員變數。
#include <iostream>
using namespace std;
class A
{
private:
static int m_nStaticNum;//宣告static member variable
private:
int m_nNum01;
int m_nNum02;
public:
A() { m_nNum01 = 10; m_nNum02 = 20; }
//宣告static member function
static int GetStaticNum() { return m_nStaticNum; }
int GetNum01() { return m_nNum01; }
//下一行編譯不會過,因為 m_nNum02 不是 static 變數
//所以取值的函式不能是宣告為 static
static int GetNum02() { return m_nNum02; }
//下一行編譯不會過,因為 GetNum01 函式不是 static 函式
//所以呼叫的函式不能是宣告為 static
static int GetNum01_2() { return GetNum01(); }
};
int A::m_nStaticNum = 0;//static member variable 的初始化
int main()
{
cout << A::GetStaticNum() << endl;
A a1;
cout << a1.GetNum01() << endl;
system("pause");
return 0;
}
.
總結一下
靜態成員變數是所有物件共用的資料,甚至不需要有物件也能使用。
靜態成員函式可以存取靜態成員變數,也是不需要有物件就能呼叫。
一般成員函式 | 靜態成員函式 | |
可存取 | 一般成員變數 靜態成員變數 | 靜態成員變數 |
可呼叫 | 一般成員函式 靜態成員函式 | 靜態成員函式 |
呼叫方式 | 一定要有物件才能呼叫 | 不需要有物件也能呼叫 |
.
不過 static 到底是要用在哪裡?
小範例1
https://husking-studio.com/cpp-static-simple-example01/
小範例2
https://husking-studio.com/cpp-static-simple-example02/
進階實驗
https://husking-studio.com/cpp-static-experiment/
像 C# 或 java 這樣的純物件導向程式語言,就因為它們是「純」物件導向程式語言,所以整個程式的運作基礎都在物件上。那程式進入點的 main 要怎麼辦?沒有 main 就沒有辦法 new 物件,沒有物件程式又不能運作,這就像是要把罐頭裡的開罐器拿出來一樣。所以它們的 main 就一定是 static 的,因為 static 不需要物件也能使用。
.
寫得非常好ㄝ 觀念清晰
謝謝大大
謝謝你 ^__^
寫得很清楚,感謝你的分享!
也謝謝你的觀看~^__^