類中的靜态成員真是個讓人愛恨交加的特性。我決定好好總結一下靜态類成員的知識點,以便自己在以後面試中,在此類問題上不在被動。
靜态類成員包括靜态資料成員和靜态函數成員兩部分。
一 靜态資料成員:
類體中的資料成員的聲明前加上static關鍵字,該資料成員就成為了該類的靜态資料成員。和其他資料成員一樣,靜态資料成員也遵守public/protected/private通路規則。同時,靜态資料成員還具有以下特點:
1.靜态資料成員的定義。
靜态資料成員實際上是類域中的全局變量。是以,靜态資料成員的定義(初始化)不應該被放在頭檔案中。
其定義方式與全局變量相同。舉例如下:
xxx.h檔案
class base
{
private:
<span style="white-space:pre"> </span>static const int _i;//聲明,标準c++支援有序類型在類體中初始化,但vc6不支援。
};
xxx.cpp檔案
const int base::_i=10;//定義(初始化)時不受private和protected通路限制.
注:不要試圖在頭檔案中定義(初始化)靜态資料成員。在大多數的情況下,這樣做會引起重複定義這樣的錯誤。即使加上#ifndef #define #endif或者#pragma once也不行。
2.靜态資料成員被 類 的所有對象所共享,包括該類派生類的對象。即派生類對象與基類對象共享基類的靜态資料成員。舉例如下:
class base
{
public :
<span style="white-space:pre"> </span>static int _num;//聲明
};
int base::_num=0;//靜态資料成員的真正定義
class derived:public base
{
};
main()
{
<span style="white-space:pre"> </span>base a;
<span style="white-space:pre"> </span>derived b;
<span style="white-space:pre"> </span>a._num++;
<span style="white-space:pre"> </span>cout<<"base class static data number _num is"<<a._num<<endl;
<span style="white-space:pre"> </span>b._num++;
<span style="white-space:pre"> </span>cout<<"derived class static data number _num is"<<b._num<<endl;
}
// 結果為1,2;可見派生類與基類共用一個靜态資料成員。
3.靜态資料成員可以成為成員函數的可選參數,而普通資料成員則不可以。舉例如下:
class base
{
public :
<span style="white-space:pre"> </span>static int _staticVar;
<span style="white-space:pre"> </span>int _var;
<span style="white-space:pre"> </span>void foo1(int i=_staticVar);//正确,_staticVar為靜态資料成員
<span style="white-space:pre"> </span>void foo2(int i=_var);//錯誤,_var為普通資料成員
};
4.★靜态資料成員的類型可以是所屬類的類型,而普通資料成員則不可以。普通資料成員的隻能聲明為 所屬類類型的 指針或引用。舉例如下:
class base
{
public :
<span style="white-space:pre"> </span>static base _object1;//正确,靜态資料成員
<span style="white-space:pre"> </span>base _object2;//錯誤
<span style="white-space:pre"> </span>base *pObject;//正确,指針
<span style="white-space:pre"> </span>base &mObject;//正确,引用
};
5.★這個特性,我不知道是屬于标準c++中的特性,還是vc6自己的特性。
靜态資料成員的值在const成員函數中可以被合法的改變。舉例如下:
class base
{
<span style="white-space:pre"> </span>public:
<span style="white-space:pre"> </span>base(){_i=0;_val=0;<span style="font-family: Tahoma, Verdana, Geneva, Arial, Helvetica, sans-serif;">}</span>
<span style="white-space:pre"> </span>mutable int _i;
<span style="white-space:pre"> </span>static int _staticVal;
<span style="white-space:pre"> </span>int _val;
<span style="white-space:pre"> </span>void test() const<span style="white-space:pre"> <span style="font-family: Tahoma, Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px;">//const 成員函數</span></span>
<span style="white-space:pre"> </span>{<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>_i++;//正确,mutable資料成員
<span style="white-space:pre"> </span>_staticVal++;//正确,static資料成員
<span style="white-space:pre"> </span>_val++;//錯誤
<span style="white-space:pre"> </span>}
};
int base::_staticVal=0;
二,靜态成員函數
靜态成員函數沒有什麼太多好講的。
1.靜态成員函數的位址可用普通函數指針儲存,而普通成員函數位址需要用 類成員函數指針來儲存。舉例如下:
class base
{
<span style="white-space:pre"> </span>static int func1();
<span style="white-space:pre"> </span>int func2();
};
int (*pf1)()=&base::func1;//普通的函數指針
int (base::*pf2)()=&base::func2;//成員函數指針
2.靜态成員函數不可以調用類的非靜态成員。因為靜态成員函數不含this指針。
3.靜态成員函數不可以同時聲明為 virtual、const、volatile函數。舉例如下:
class base
{
<span style="white-space:pre"> </span>virtual static void func1();//錯誤
<span style="white-space:pre"> </span>static void func2() const;//錯誤
<span style="white-space:pre"> </span>static void func3() volatile;//錯誤
};
最後要說的一點是,靜态成員是可以獨立通路的,也就是說,無須建立任何對象執行個體就可以通路。