獨一無二----靜態成員變數 (轉)

worldblog發表於2007-12-10
獨一無二----靜態成員變數 (轉)[@more@]

獨一無二:namespace prefix = o ns = "urn:schemas--com::office" />

  ----靜態成員變數

作者:HolyFire

我們學習C++的時候知道靜態變數的特性,他不是臨時變數,在編譯期間就已經產成。用一個例子就能說明問題。

#include

using namespace std;

class A{

public:

  A(){ cout << "Can you see me Now!" << endl; }

  ~A(){ cout << "I'm Go Away!" << endl; }

};

void TestStatic( void )

{

  static A a;

}

void main()

{

  cout << "Program Start!" << endl;

  TestStatic();

  TestStatic();

  TestStatic();

  cout << "Program End!" << endl;

}

結果是:

Program Start!

Can you see me Now!

Program End!

I'm Go Away!

A a只被定義了一次,而且析構是在主退出以後才進行的。這說明了什麼呢,A a在void TestStatic( void )是同一個例項,他存在於整個程式但是隻有在void TestStatic( void )中能訪問他。

不相信?那我們來試試看。

#include

using namespace std;

class A{

private:

  int count;

public:

  A():count(0){ cout << "Can you see me Now!" << endl; }

  ~A(){ cout << "I'm Go Away!" << endl; }

  void Inc(){ count++; }

  int Count(){ return count; }

};

void TestStatic( void )

{

  static A a;

  a.Inc();

  cout << "count's value is : " << a.Count() << endl;

}

void main()

{

  cout << "Program Start!" << endl;

  TestStatic();

  TestStatic();

  TestStatic();

  cout << "Program End!" << endl;

}

結果是:

Program Start!

Can you see me Now!

count's value is : 1  //初始化count為0,Inc導致count自加值應該為1

count's value is : 2  //沒有初始化,Inc導致count自加值應該為2

count's value is : 3  //沒有初始化,Inc導致count自加值應該為3

Program End!

I'm Go Away!

事實說明了一切,那麼他是如何實現的呢,C++裡,他被建立在一個區域裡,這塊區域不是堆也不是棧,編譯器在編譯階段就將他們記住,併為他們做好分配工作,如此一來就可以實現這個特性。

看起來他的作用有些象全域性變數,但是我們知道,使用全域性變數會整加模組的耦合性,降低程式碼的通用性,所以靜態成員變數的出現為我們帶來的靈活性。

如何將這個小東西用在我們的面向程式設計中呢。他扮演一個什麼樣的角色呢,這正是我要說的。

我們知道,類的成員變數表示了一個類的屬性,對應著物件的物質特性,他們在類的某個例項建立的時候建立,消亡的時候消亡。但是上面說到,靜態變數在編譯期間就已經存在了,也就是並不隨著例項建立的時候建立,消亡的時候消亡。是這樣嗎。看事實說話。

#include

using namespace std;

class A{

public:

  A() { cout << "A is On!" << endl; }

  ~A() { cout << "A is OFF!" << endl; }

};

class B{

public:

  B() { cout << "B is On!" << endl; }

   ~B() { cout << "B is OFF!" << endl; }

private:

  static A a;

};

A B::a;

void main()

{

  cout << "Program Start!" << endl;

  B b1,b2,b3;

  cout << "Program End!" << endl;

}

結果是:

A is On!  //瞧我又說中了,主程式還沒有執行,構造就開始工作了,這時B的例項還沒有登場

Program Start!

B is On!  //b1建立了,但是b1.a並沒有建立

B is On!

B is On!

Program End!

B is OFF!  //B的例項銷燬了,但是成員變數a沒有銷燬

B is OFF!

B is OFF!

A is OFF!  //看吧,這才是A的解構函式

注意一個約定:

A B::a;

靜態成員變數的初始化一定要在主函式外面,而且靜態成員變數一定要初始化。

事實上B::a並不屬於B,將他作為B的成員只是為了確定訪問的

private:

  static A a;

因為這樣設定以後只有B才能訪問B::a,當然設計的時候要考慮清楚,如果a與B並沒有關係,那麼這樣的設計就沒有什麼實際的意義。

那麼如何設計才能運用這個特性呢。

我們來舉個例子。

我們有時候想知道類的例項有幾個,也就是被例項化了幾次。比如

class A;

A a1,a2,a3;

那麼就應該被例項化了3次。能知道這個資訊應該很不錯。如果用一個全域性變數,那麼要考慮的問題很多,全域性變數會被人任意修改,全域性變數定義在那裡以及全域性變數初始化在那裡也會帶來困惑,全域性變數會不會跟別的全域性變數重名等等。

既然靜態變數可以實現一些全域性變數的功能,何不牛刀小試,看看效果如何。首先靜態成員變數只有一個,而且不是類的真實屬性,實際上只有一個變數,不會增加類的負擔;第二可以給他加上訪問限制,只要不是public那麼就不能隨意修改。既然好處多多,那麼就開工。

#include

using namespace std;

class A{

public:

  A(){ count++; };  //當產生一個例項的時候計數器加一

  ~A(){ count--; }  //當銷燬一個例項的時候計數器減一

  int GetInstanceCount(){ return count; }

private:

  static int count;

};

int A::count = 0;

void main()

{

  cout << "Program Start! " << endl << endl;

  A a1,a2,a3;

  {

  A a4,a5,*pa;

  cout << "Now, Have a1 ,a2 ,a3 , a4 ,a5 Instances!" << endl;

  cout << "Number of class A's Instance is : " << a1.GetInstanceCount() << endl << endl;

  pa = new A;

  cout << "Now Creat a class A's Instance!" << endl;

  cout << "Number of class A's Instance is : " << a2.GetInstanceCount() << endl << endl;

  delete pa;

  }

  cout << "While class's Instances a4 , a5 , pa destroy!" << endl;

  cout << "Only a1 , a2 , a3 Left , is the Count of Instance is 3 ?" << endl;

  cout << "Number of class A's Instance is : " << a3.GetInstanceCount() << endl << endl ;

}

結果是:

Program Start!

Now, Have a1 ,a2 ,a3 , a4 ,a5 Instances!  //有a1 ,a2 ,a3 ,a4 ,a5五個例項

Number of class A's Instance is : 5  //沒錯,正是五個

Now Creat a class A's Instance!  //在堆裡建立了一個,使用pa得到他的引用

Number of class A's Instance is : 6  //跟想的一樣,數目增加了

While class's Instances a4 , a5 , pa destroy!  //在堆裡釋放一個,棧裡釋放2個

Only a1 , a2 , a3 Left , is the Count of Instance is 3 ? //6 – 1 –2 當然等於3啦

Number of class A's Instance is : 3  我說的沒錯吧。

因為在建構函式里操作的是同一個變數,所以才能得到正確的結果。這個技術在很多方面得到應用,比如,互斥訊號,象動態連線庫一樣的引用計數器等等。

這裡要記住的是,類的靜態成員變數實際上只有一個,它不隨著類的例項的建立/銷燬而增加/減少。它不是類的真正成員,並不是類的一部分。

2001/9/7

丁寧 


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-990749/,如需轉載,請註明出處,否則將追究法律責任。

相關文章