一個類成員函數的局部靜態變量問題


  之前工作中遇到一個問題,就像題目中描述的那樣,看起來題目有些拗口復雜,這里解釋下,當時遇到的需求需要這樣處理:調用某個類對象的某個成員函數時,第一次有具體意義的,其他時候都是保持不變的、無意義的。這個需求可以看做是在調用某成員函數時,第一次進行初始化,其他時候不進行操作,即在首次調用時進行初始化,根據這點,很容易想到c/c++里面的static變量,它的作用是保持變量內容的持久,存儲在靜態數據區的變量會在程序剛開始運行時就完成初始化,也是唯一的一次初始化。根據需求,使用static局部變量,寫下如下代碼:

 1 class T  2 {  3 public:  4     T(const char * pstr):value(pstr){}  5     void Print()const;  6 private:  7     string value;  8 };  9 
10 void T::Print()const
11 { 12     static bool bFirstCall = true; 13     if(bFirstCall) 14  { 15         cout<<"first Call "<<value<<endl; 16         bFirstCall = false; 17  } 18     else
19  { 20         cout<<"not first Call "<<value<<endl; 21  } 22 } 

即在類的成員函數中定義一個局部的靜態變量,使得第一次調用進行初始化,用以區分是否是第一次調用,之后運行else分支。運行下面的測試代碼,輸出結果見下圖:

 1 int _tmain(int argc, _TCHAR* argv[])  2 {  3     T t1("Grubby");  4  t1.Print();  5  t1.Print();  6 
 7     T t2("Moon");  8  t2.Print();  9  t2.Print(); 10 
11     return 0; 12 }

通過輸出可以看到,t1得到了想要的結果,但是兩次t2.Print()都打印 "not first Moon",這說明此時 bFirstCall 還是false。於是在Print函數中打印bFirstCall地址的代碼:

 1 void T::Print()const
 2 {  3     static bool bFirstCall = true;  4     printf("addr of bFirstCall is %x\n", &bFirstCall);  5     if(bFirstCall)  6  {  7         cout<<"first Call "<<value<<endl;  8         bFirstCall = false;  9  } 10     else
11  { 12         cout<<"not first Call "<<value<<endl; 13  } 14 }

再次運行輸出如下:

看到四次調用Print函數時打印的bFirstCall的地址相同,這說明類成員函數中的局部靜態變量同樣屬於此函數,而不屬於某個對象,不會因為重新定義一個t2對象,第一次調用 t2.Print()時 bFristCall 是 true,不管是哪個T類對象,只在第一次調用 Print()時,bFirstCall == ture。於是無奈對程序進行了修改,將bFristCall定義為類的靜態成員,每次構造函數是將其重置為true:

 1 class T  2 {  3 public:  4     T(const char * pstr):value(pstr){ bFirstCall = true;}  5     void Print()const;  6 private:  7     string value;  8     static bool bFirstCall;  9 }; 10 bool T::bFirstCall; 11  
12 void T::Print()const
13 { 14     if(bFirstCall) 15  { 16         cout<<"first Call "<<value<<endl; 17         bFirstCall = false; 18  } 19     else
20  { 21         cout<<"not first Call "<<value<<endl; 22  } 23 }

運行測試代碼可以得到想要的結果:

但是這里又出現了新的問題,即每次構造函數是將bFirstCall重置為true時,如果新定義一個對象,並且沒有調用Print()函數,那么再次調用之前定義對象的Print()函數,會產生與預期相反的結果,考慮如下測試代碼:

 1 int _tmain(int argc, _TCHAR* argv[])  2 {  3     T t1("Grubby");  4  t1.Print();  5  t1.Print();  6 
 7     T t2("Moon");  8  t1.Print();  9 
10     return 0; 11 }

運行輸出如下:

避免這種情況,目前只能保證順序的對每個對象進行類似Print這樣函數的初始化調用,還沒有想到好的解決辦法。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM