static在C和C++裏各表明什麼含義

轉自:http://blog.csdn.net/wanglongfei_hust/article/details/10011503ios


static關鍵字有三種使用方式,其中前兩種只指在C語言中使用,第三種在C++中使用。c++


1. 局部靜態變量(C)

2. 外部靜態變量/函數(C)

3. 靜態數據成員/成員函數(C++)


1、 局部靜態變量

局部變量按照存儲形式能夠分爲三種,分別是auto、static、register。

與auto類型(普通)局部變量相比,static有三點不一樣:

1. 存儲空間分配不一樣

       auto類型分配在棧上,屬於動態存儲類別,佔動態存儲空間,函數調用結束後自動釋放;

       static類型分配在靜態存儲區,在程序整個運行期間都不釋放;

       二者做用域相同,可是生存期不一樣。

2. static局部變量在初次運行時進行初始化工做,且只初始化一次。

3. 對於局部靜態變量,若是不賦初值,編譯期會自動賦初值0或者空;

auto類型的初值是不肯定的。

對於C++的類對象例外,class的對象實例若是不初始化,則會自動調用默認構造函數,不論是不是static類型。

特色:static局部變量的「記憶性」與生存期的「全局性」

所謂「記憶性」是指在兩次函數調用時,在第二次調用進入時,能保持第一次調用退出時的值。

示例程序一

多線程

  1. #include <iostream>    
  2. using namespace std;    
  3.     
  4. void staticLocalVar()    
  5. {    
  6.     static int a = 0;    
  7.     cout<<"a="<<++a<<endl;    
  8. }    
  9.     
  10. int main()    
  11. {    
  12.     staticLocalVar();   // a=1    
  13.     staticLocalVar();   // a=2    
  14.     system("pause");    
  15.     return 0;    
  16. }    

運行結果:函數

 

a=1this

a=2spa

請按任意鍵繼續. . ..net


應用:利用「記憶性」記錄函數調用的次數(示例程序一)
利用生存期的」全局性「改善return a pointer / reference to a local object的問題,local object的問題在於退出函數時,生存期就結束,局部變量就會被銷燬;利用static就能夠延長局部變量的生存期。

注意事項:
1. 「記憶性」是程序運行很重要的一點就是可重複性,而static變量的「記憶性」破壞了可重複性,形成不一樣時刻同一函數的運行結果不一樣。

2. 「生存期」全局性和惟一性。 普通的局部變量在棧上分配空間,所以每次調用函數時,分配的空間均可能不同,而static具備全局惟一性的特色,每次調用時都指向同一塊內存,這就形成一個很重要的問題---不可重入性!!!

在多線程或者遞歸程序中要特別注意。

2、 外部靜態變量/函數

在C中static的第二種含義:用來表示不能被其它文件訪問的全局變量和函數。

此處static的含義是指對函數的做用域僅僅侷限於本文件(因此又稱爲內部函數)。

注意:對於外部(全局)變量,不管是否有static限制,它的存儲區域都是在靜態存儲區,生存期都是全局的,此時的static只是起做用域限制做用,限制做用域在本文件內部。

使用內部函數的好處是:不一樣的人編寫不一樣的函數時,不用擔憂函數同名問題。

示例程序二
線程

  1. //file1.cpp     
  2. static int varA;     
  3. int varB;     
  4. extern void funA()     
  5. {      
  6. }     
  7.     
  8. static void funB()     
  9. {     
  10. }     
  11.     
  12. //file2.cpp     
  13. extern int varB; // 使用file1.cpp中定義的全局變量     
  14. extern int varA; // 錯誤! varA是static類型, 沒法在其餘文件中使用     
  15. extern void funA(); // 使用file1.cpp中定義的函數     
  16. extern void funB(); // 錯誤! 沒法使用file1.cpp文件中static函數     


3、 靜態數據成員/成員函數(C++特有)指針


C++重用了這個關鍵字,它表示屬於一個類而不是屬於此類的任何特定的對象的變量和函數。

靜態類成員包括靜態數據成員和靜態函數成員。

1. 靜態數據成員

       類體中的數據成員的聲明前加上static關鍵字,該數據成員就成爲了該類的靜態數據成員。和其餘數據成員同樣,靜態數據成員也遵照public/protected/private訪問規則。同時靜態數據成員還具備如下特色。

1) 靜態數據成員的定義

      靜態數據成員其實是類域中的全局變量。因此,靜態數據成員的定義(初始化)不該該被放在頭文件中。其定義方式與全局變量相同。舉例以下:
code

  1.  xxx.h文件            
  2.  class base    
  3. {               
  4. private:         
  5.     static const int _i;    //聲明,標準c++支持有序類型在類體中初始化,但vc6不支持。      
  6. };       
  7.     
  8. xxx.cpp文件              
  9. const int base::_i = 10;    //定義(初始化)時不受private和protected訪問限制.     

  
注:不要試圖在頭文件中定義(初始化)靜態數據成員。在大多數狀況下,這會引發重複定義。即便加上#ifndef  #define  #endif或者#pragma once也不行。

2) 靜態數據成員被類的全部對象所共享,包括該類的派生類的對象。


  1. #include <iostream>    
  2. using namespace std;    
  3.     
  4. class base    
  5. {                    
  6. public:                   
  7.     static int _num;    //聲明              
  8. };      
  9.             
  10. int base::_num = 0; //靜態數據成員的真正定義         
  11.             
  12. class derived : public base    
  13. {              
  14. };        
  15.          
  16. int main()              
  17. {                 
  18.     base a;                 
  19.     derived b;              
  20.     a._num++;                 
  21.     cout<<"base class static data number _num is "<<a._num<<endl; // 1               
  22.     b._num++;                
  23.     cout<<"derived class static data number _num is "<<b._num<<endl;// 2    
  24.     system("pause");    
  25.     return 0;    
  26. }    


3) 靜態數據成員能夠成爲成員函數的可選參數,而普通數據成員則不能夠。

  1. class base    
  2. {      
  3. public:                
  4.     static int _staticVar;      
  5.     int _var;      
  6.     void foo1(int i = _staticVar);//正確,_staticVar爲靜態數據成員        
  7.     void foo2(int i = _var);//錯誤,_var爲普通數據成員      
  8. };      


 4)★靜態數據成員的類型能夠是所屬類的類型,而普通數據成員則不能夠。普通數據成員的只能聲明爲所屬類類型的指針或引用。舉例以下:

  1. class base    
  2. {                
  3. public:              
  4.     static base _object1;//正確,靜態數據成員             
  5.     base  object2;//錯誤            
  6.     base *pObject;//正確,指針         
  7.     base &mObject;//正確,引用        
  8. };    


5)  靜態數據成員的值在const成員函數中能夠被合法的改變。舉例以下:

  1. class base    
  2. {                
  3. public:                
  4.     base()    
  5.     {    
  6.         _i = 0;    
  7.         _val = 0;    
  8.     }               
  9.     mutable int _i;            
  10.     static int _staticVal;            
  11.     int _val;            
  12.     void test() const    
  13.     {      
  14.         _i++;//正確,mutable數據成員                 
  15.         _staticVal++;//正確,static數據成員                    
  16.         _val++;//錯誤                
  17.     }            
  18. };            
  19. int   base::_staticVal = 0;     



2. 靜態成員函數   

1).靜態成員函數的地址可用普通函數指針儲存,而普通成員函數地址須要用類成員函數指針來儲存。舉例以下:

  1. class base    
  2. {                   
  3.     static int func1();                   
  4.     int func2();                
  5. };      
  6.              
  7. int (*pf1)() = &base::func1;        //普通的函數指針             
  8. int (base::*pf2)() = &base::func2;  //成員函數指針      


2).靜態成員函數不能夠調用類的非靜態成員。由於靜態成員函數不含this指針。  
3).靜態成員函數不能夠同時聲明爲   virtual、const、volatile函數。舉例以下:

  1. class base    
  2. {                   
  3.     virtual static void func1();//錯誤         
  4.     static void func2() const;//錯誤          
  5.     static void func3() volatile;//錯誤              
  6. };     

最後要說的一點是,靜態成員是能夠獨立訪問的,也就是說,無須建立任何對象實例就能夠訪問。

相關文章
相關標籤/搜索