static有兩種用法:面向過程程序設計中的static和麪向對象程序設計中的static。前者應用於普通變量和函數,不涉及類;後者主要說明static在類中的做用。
面向過程設計中的static
全局變量、局部變量、靜態全局變量、靜態局部變量的區別
C++變量根據定義的位置的不一樣的生命週期,具備不一樣的做用域,做用域可分爲6種:全局做用域,局部做用域,語句做用域,類做用域,命名空間做用域和文件做用域。
從做用域看:
全局變量具備全局做用域。全局變量只需在一個源文件中定義,就能夠做用於全部的源文件。固然,其餘不包含全局變量定義的源文件須要用extern 關鍵字再次聲明這個全局變量。
靜態局部變量具備局部做用域,它只被初始化一次,自從第一次被初始化直到程序運行結束都一直存在,它和全局變量的區別在於全局變量對全部的函數都是可見的,而靜態局部變量只對定義本身的函數體始終可見。
局部變量也只有局部做用域,它是自動對象(auto),它在程序運行期間不是一直存在,而是隻在函數執行期間存在,函數的一次調用執行結束後,變量被撤銷,其所佔用的內存也被收回。
靜態全局變量也具備全局做用域,它與全局變量的區別在於若是程序包含多個文件的話,它做用於定義它的文件裏,不能做用到其它文件裏,即被static關鍵字修飾過的變量具備文件做用域。這樣即便兩個不一樣的源文件都定義了相同名字的靜態全局變量,它們也是不一樣的變量。
從分配內存空間看:
全局變量,靜態局部變量,靜態全局變量都在靜態存儲區分配空間,而局部變量在棧裏分配空間
全局變量自己就是靜態存儲方式, 靜態全局變量固然也是靜態存儲方式。這二者在存儲方式上並沒有不一樣。這二者的區別雖在於非靜態全局變量的做用域是整個源程序,當一個源程序由多個源文件組成 時,非靜態的全局變量在各個源文件中都是有效的。 而靜態全局變量則限制了其做用域, 即只在定義該變量的源文件內有效,在同一源程序的其它源文件中不能使用它。因爲靜態全局變量的做用域侷限於一個源文件內,只能爲該源文件內的函數公用,因 此能夠避免在其它源文件中引發錯誤。
1)、靜態變量會被放在程序的靜態數據存儲區(數據段)(全局可見)中,這樣能夠在下一次調用的時候還能夠保持原來的賦值。這一點是它與堆棧變量和堆變量的區別。
2)、變量用static告知編譯器,本身僅僅在變量的做用範圍內可見。這一點是它與全局變量的區別。
從以上分析能夠看出, 把局部變量改變爲靜態變量後是改變了它的存儲方式即改變了它的生存期。把全局變量改變爲靜態變量後是改變了它的做用域,限制了它的使用範圍。所以static 這個說明符在不一樣的地方所起的做用是不一樣的。應予以注意。
Tips:
A.若全局變量僅在單個C文件中訪問,則能夠將這個變量修改成靜態全局變量,以下降模塊間的耦合度;
B.若全局變量僅由單個函數訪問,則能夠將這個變量改成該函數的靜態局部變量,以下降模塊間的耦合度;
C.設計和使用訪問動態全局變量、靜態全局變量、靜態局部變量的函數時,須要考慮重入問題,由於他們都放在靜態數據存儲區,全局可見;
D.若是咱們須要一個可重入的函數,那麼,咱們必定要避免函數中使用static變量(這樣的函數被稱爲:帶「內部存儲器」功能的的函數)
E.函數中必需要使用static變量狀況:好比當某函數的返回值爲指針類型時,則必須是static的局部變量的地址做爲返回值,若爲auto類型,則返回爲錯指針。
-----------------------------------------------------------------------------------------------------------
static 全局變量:改變做用範圍,不改變存儲位置
static 局部變量:改變存儲位置,不改變做用範圍
靜態函數 :在函數的返回類型前加上static關鍵字,函數即被定義爲靜態函數。靜態函數與普通函數不一樣,它只能在聲明它的文件當中可見,不能被其它文件使用。
若是在一個源文件中定義的函數,只能被本文件中的函數調用,而不能被同一程序其它文件中的函數調用,這種函數也稱爲內部函數。定義一個內部函數,只需在函數類型前再加一個「static」關鍵字便可。
---------------------------------------------------------------------------------------------------------------
2、面向對象的static關鍵字(類中的static關鍵字)
靜態數據成員有如下特色:
對於非靜態數據成員,每一個類對象都有本身的拷貝。而靜態數據成員被看成是類的成員。不管這個類的對象被定義了多少個,靜態數據成員在程序中也只有一份 拷 貝,由該類型的全部對象共享訪問。也就是說,靜態數據成員是該類的全部對象所共有的。對該類的多個對象來講,靜態數據成員只分配一次內存,供全部對象共 用。因此,靜態數據成員的值對每一個對象都是同樣的,它的值能夠更新;
靜態數據成員存儲在全局數據區。靜態數據成員定義時要分配空間,因此不能在類聲明中定義。在Example 5中,語句int Myclass::Sum=0;是定義靜態數據成員;
靜態數據成員和普通數據成員同樣聽從public,protected,private訪問規則;
由於靜態數據成員在全局數據區分配內存,屬於本類的全部對象共享,因此,它不屬於特定的類對象,在沒有產生類對象時其做用域就可見,即在沒有產生類的實例時,咱們就能夠操做它;
靜態數據成員初始化與通常數據成員初始化不一樣。靜態數據成員初始化的格式爲:
<數據類型><類名>::<靜態數據成員名>=<值>
類的靜態數據成員有兩種訪問形式:
<類對象名>.<靜態數據成員名> 或 <類類型名>::<靜態數據成員名>
若是靜態數據成員的訪問權限容許的話(即public的成員),可在程序中,按上述格式來引用靜態數據成員 ;
靜態數據成員主要用在各個對象都有相同的某項屬性的時候。好比對於一個存款類,每一個實例的利息都是相同的。因此,應該把利息設爲存款類的靜態數據成 員。這 有兩個好處,第一,無論定義多少個存款類對象,利息數據成員都共享分配在全局數據區的內存,因此節省存儲空間。第二,一旦利息須要改變時,只要改變一次, 則全部存款類對象的利息全改變過來了;
同全局變量相比,使用靜態數據成員有兩個優點:
靜態數據成員沒有進入程序的全局名字空間,所以不存在與程序中其它全局名字衝突的可能性;
能夠實現信息隱藏。靜態數據成員能夠是private成員,而全局變量不能;
二、靜態成員函數
與靜態數據成員同樣,咱們也能夠建立一個靜態成員函數,它爲類的所有服務而不是爲某一個類的具體對象服務。靜態成員函數與靜態數據成員同樣,都是類的 內部 實現,屬於類定義的一部分。 普通的成員函數通常都隱含了一個this指針,this指針指向類的對象自己,由於普通成員函數老是具體的屬於某個類的具體對象的。一般狀況下,this 是缺省的。如函數fn()其實是this->fn()。可是與普通函數相比,靜態成員函數因爲不是與任何的對象相聯繫,所以它不具備this指 針。從這個意義上講,它沒法訪問屬於類對象的非靜態數據成員,也沒法訪問非靜態成員函數,它只能調用其他的靜態成員函數。
關於靜態成員函數,能夠總結爲如下幾點:
出如今類體外的函數定義不能指定關鍵字static;
靜態成員之間能夠相互訪問,包括靜態成員函數訪問靜態數據成員和訪問靜態成員函數;
非靜態成員函數能夠任意地訪問靜態成員函數和靜態數據成員;
靜態成員函數不能訪問非靜態成員函數和非靜態數據成員;
因爲沒有this指針的額外開銷,所以靜態成員函數與類的全局函數相比速度上會有少量的增加;
調用靜態成員函數,能夠用成員訪問操做符(.)和(->)爲一個類的對象或指向類對象的指針調用靜態成員函數,也能夠直接使用以下格式:
<類名>::<靜態成員函數名>(<參數表>)
調用類的靜態成員函數。
===============================================================================================
static靜態變量聲明符。 在聲明它的程序塊,子程序塊或函數內部有效,值保持,在整個程序期間分配存儲器空間,編譯器默認值0。
是C++中很經常使用的修飾符,它被用來控制變量的存儲方式和可見性。
二、爲何要引入static?
函數內部定義的變量,在程序執行到它的定義處時,編譯器爲它在棧上分配空間,你們知道,函數在棧上分配的空間在此函數執行結束時會釋放掉,這樣就產生 了一個問題: 若是想將函數中此變量的值保存至下一次調用時,如何實現? 最容易想到的方法是定義一個全局的變量,但定義爲一個全局變量有許多缺點,最明顯的缺點是破壞了此變量的訪問範圍(使得在此函數中定義的變量,不只僅受此 函數控制)。
三、何時用static?
須要一個數據對象爲整個類而非某個對象服務,同時又力求不破壞類的封裝性,即要求此成員隱藏在類的內部,對外不可見。
四、static的內部機制:
靜態數據成員要在程序一開始運行時就必須存在。由於函數在程序運行中被調用,因此靜態數據成員不能在任何函數內分配空間和初始化。
這樣,它的空間分配有三個可能的地方,一是做爲類的外部接口的頭文件,那裏有類聲明;二是類定義的內部實現,那裏有類的成員函數定義;三是應用程序的main()函數前的全局數據聲明和定義處。
靜態數據成員要實際地分配空間,故不能在類的聲明中定義(只能聲明數據成員)。類聲明只聲明一個類的「尺寸和規格」,並不進行實際的內存分配,因此在 類聲明中寫成定義是錯誤的。它也不能在頭文件中類聲明的外部定義,由於那會形成在多個使用該類的源文件中,對其重複定義。
static被引入以告知編譯器,將變量存儲在程序的靜態存儲區而非棧上空間,靜態
數據成員按定義出現的前後順序依次初始化,注意靜態成員嵌套時,要保證所嵌套的成員已經初始化了。消除時的順序是初始化的反順序。
五、static的優點:
能夠節省內存,由於它是全部對象所公有的,所以,對多個對象來講,靜態數據成員只存儲一處,供全部對象共用。靜態數據成員的值對每一個對象都是同樣,但它的值是能夠更新的。只要對靜態數據成員的值更新一次,保證全部對象存取更新後的相同的值,這樣能夠提升時間效率。
六、引用靜態數據成員時,採用以下格式:
<類名>::<靜態成員名>
若是靜態數據成員的訪問權限容許的話(即public的成員),可在程序中,按上述格式
來引用靜態數據成員。
七、注意事項:
(1)類的靜態成員函數是屬於整個類而非類的對象,因此它沒有this指針,這就致使
了它僅能訪問類的靜態數據和靜態成員函數。
(2)不能將靜態成員函數定義爲虛函數。
(3)因爲靜態成員聲明於類中,操做於其外,因此對其取地址操做,就多少有些特殊
,變量地址是指向其數據類型的指針 ,函數地址類型是一個「nonmember函數指針」。
(4)因爲靜態成員函數沒有this指針,因此就差很少等同於nonmember函數,結果就
產生了一個意想不到的好處:成爲一個callback函數,使得咱們得以將C++和C-based X W
indow系統結合,同時也成功的應用於線程函數身上。
(5)static並無增長程序的時空開銷,相反她還縮短了子類對父類靜態成員的訪問
時間,節省了子類的內存空間。
(6)靜態數據成員在<定義或說明>時前面加關鍵字static。
(7)靜態數據成員是靜態存儲的,因此必須對它進行初始化。
(8)靜態成員初始化與通常數據成員初始化不一樣:
初始化在類體外進行,而前面不加static,以避免與通常靜態變量或對象相混淆;
初始化時不加該成員的訪問權限控制符private,public等;
初始化時使用做用域運算符來標明它所屬類;
因此咱們得出靜態數據成員初始化的格式:
<數據類型><類名>::<靜態數據成員名>=<值>
(9)爲了防止父類的影響,能夠在子類定義一個與父類相同的靜態變量,以屏蔽父類的影響。這裏有一點須要注意:咱們說靜態成員爲父類和子類共享,但我 們有重複定義了靜態成員,這會不會引發錯誤呢?不會,咱們的編譯器採用了一種絕妙的手法:name-mangling 用以生成惟一的標誌。html