C++ 的 static -靜態變數與函式詳細說明

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 不需要物件也能使用。

.

在〈C++ 的 static -靜態變數與函式詳細說明〉中有 4 則留言

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *