1 靜態成員變量
1.1 定義靜態成員變量
-
關鍵字
static
可以用於說明一個類的成員 -
靜態成員提供了一個同類對象的共享機制
-
把一個類的成員說明
static
時,無論這個類有多少對象被創建,這些對象共享這個static
成員 -
靜態成員局部於類,他不是對象的成員
如同下圖所示,對於同類定義出來的對象
A,B,C,D
其中成員變量是ch
是每個對象自己特有,但是靜態成員變量s是全體對象共用,只要有一個對象修改了這個s
的值,則全部相同類定義的對象中的s
都發生改變。

如同上圖所示,對於同類定義出來的對象A,B,C,D
其中成員變量是ch
是每個對象自己特有,但是靜態成員變量s是全體對象共用,只要有一個對象修改了這個s
的值,則全部相同類定義的對象中的s
都發生改變。
#include<iostream.h>
class counter
{
public :
counter (int a)
{
mem = a;
}
int mem; //公有數據成員
static int Smem ; //公有靜態數據成員
} ;

int counter :: Smem = 1; //初始值為1
void main()
{ counter c(5);
int i ;
for( i = 0 ; i < 5 ; i ++ )
{ counter::Smem += i ;
cout << counter::Smem << '\t' ; //訪問靜態成員變量方法2
}
cout<<endl; cout<<"c.smem="<<c.Smem<<endl; //訪問靜態成員變量方法1
cout<<" c.mem="<<c.mem<<endl;
}
1.2 靜態成員函數
- 靜態成員變量冠以關鍵詞
static
- 靜態成員變量是不依賴類數據結構的共同操作
- 在類外調用靜態成員變量是有 類名::作為限定詞,或者通過對象進行調用
舉個例子
class X
{
public:
static void printfID()
{
// count<<id<<endl; 錯誤做法
count<<s_id<<endl; //正確做法
}
private:
int id;
static int s_id;
}
//使用static 修飾的變量是屬於整個類,所有的對象都可以共用
其中 // count<<id<<endl;
是錯誤,原因如下圖所示:

對於每一個對象都存在一個獨有的id
變量,但是對於static
修飾的函數是共用,如果使用static
函數通用普通的的成員變量就無法區分是哪一個對象的id
變量。
1.3使用static的好處(參考)
-
第一個好處肯定就是占用內存小,不需要對每一個對象都分配函數空間。
-
可以實現某些特殊的設計模式:如
Singleton
; -
可以封裝某些算法,比如數學函數,如
ln,sin,tan
等等,這些函數本就沒必要屬於任何一個對象,所以從類上調用感覺更好,比如定義一個數學函數類Math,調用Math::sin(3.14);如果非要用非靜態函數,那就必須:Math math; math.sin(3.14);
行是行,只是不爽:就為了一個根本無狀態存儲可言的數學函數還要引入一次對象的構造和一次對象的析構,當然不爽。而且既然有了對象,說不得你還得小心翼翼的定義拷貝構造函數、拷貝賦值運算符等等,對於一些純算法的東西顯然是不合適的。 -
由於沒有this指針,可以把某些系統API的回調函數以靜態函數的形式封裝到類的內部。因為系統API的回調函數通常都是那種非成員函數(孤立函 數),沒有this指針的。比如你可以在類的內部寫一個線程函數供
CreateThread
創建線程用,如果沒有靜態函數,那么這種回調函數就必須定義成 全局函數(非靜態成員函數指針無法轉換成全局函數指針),從而影響了OO的“封裝性”。 -
總之,從OOA/OOD的角度考慮,一切不需要實例化就可以有確定行為方式的函數都應該設計成靜態的。
以上只是一些基本的考慮,並不是絕對的。絕對東西的只有一點:“靜態函數不需要實例化就可以被調用,不會也不可以調用或操縱非靜態成員”。記住這一點,那么實際編程中何時需要用,何時適合用,自然就更容易作出決定了。