獨一無二----靜態成員變數 (轉)
獨一無二: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/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 類的靜態成員變數和普通成員變數該怎樣去區別定義變數
- C++類的靜態成員變數初始化C++變數
- 成員變數、全域性變數、例項變數、類變數、靜態變數和區域性變數的區別變數
- Java靜態變數在靜態方法內部無法改變值Java變數
- C++學習筆記(三):類與物件--靜態成員變數與常成員函式C++筆記物件變數函式
- C++ 的靜態成員變數為什麼一定要在類外定義C++變數
- 靜態變數變數
- c#物件導向- 靜態成員和非靜態成員的區別C#物件
- 成員變數變數
- c++類的靜態成員C++
- C++ 靜態資料成員C++
- C++:類的靜態成員C++
- c++中的靜態成員C++
- TypeScript 中 class 的例項成員與靜態成員TypeScript
- C++類中的常成員和靜態成員C++
- 【C++】靜態持續變數?如何建立靜態持續變數?C++變數
- 類內的靜態成員函式函式
- ConcurrentHashMap(一):常量,成員變數,靜態程式碼塊,內部類,spread函式,tabAt函式等詳解HashMap變數函式BAT
- 獨一無二的出現次數
- 區域性變數和全域性變數(靜態和非靜態)區別變數
- 成員變數和區域性變數變數
- Java中變數之區域性變數、本類成員變數、父類成員變數的訪問方法Java變數
- 在Python中將字典轉為成員變數的方法Python變數
- 12 ### 各種成員變數變數
- C#快速入門教程(3)——類的靜態成員和例項成員C#
- 1207. 獨一無二的出現次數
- 子父類中成員變數變數
- Spring如何為靜態變數注入值Spring變數
- 對於systemverilog靜態變數和動態變數 ,描述不正確的是()。變數
- static 靜態變數引起 Laravel 中佇列一個 Bug變數Laravel佇列
- [LeetCode]1207. 獨一無二的出現次數LeetCode
- oop類的繼承與類靜態成員學習OOP繼承
- Python中類變數、成員變數、區域性變數的區別Python變數
- c++成員變數初始化C++變數
- 類成員變數的初始化變數
- C語言--靜態區域性變數C語言變數
- Java逆向基礎之靜態變數存取Java變數
- Java自學入門之靜態變數Java變數
- 類,物件,成員變數和區域性變數,匿名物件物件變數