C|C++中的靜態全局變量,靜態局部變量,全局變量,局部變量的區別


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”關鍵字即
可。   
---------------------------------------------------------------------------------------------------------------   


二、面向對象的static 關鍵字(類中的static 關鍵字)   


靜態數據成員有以下特點:   
對於非靜態數據成員,每個類對象都有自己的拷貝。而靜態數據成員被當作是類的成員。無論這個類的對
象被定義了多少個,靜態數據成員在程序中也只有一份 拷 貝,由該類型的所有對象共享訪問。也就是說,
靜態數據成員是該類的所有對象所共有的。對該類的多個對象來說,靜態數據成員只分配一次內存,供所
有對象共 用。所以,靜態數據成員的值對每個對象都是一樣的,它的值可以更新;   
靜態數據成員存儲在全局數據區。靜態數據成員定義時要分配空間,所以不能在類聲明中定義。在 Example
5中,語句int Myclass::Sum=0;是定義靜態數據成員;   
靜態數據成員和普通數據成員一樣遵從 public,protected,private 訪問規則;   
因為靜態數據成員在全局數據區分配內存,屬於本類的所有對象共享,所以,它不屬於特定的類對象,在
沒有產生類對象時其作用域就可見,即在沒有產生類的實例時,我們就可以操作它;   
靜態數據成員初始化與一般數據成員初始化不同。靜態數據成員初始化的格式為:   
<數據類型><類名>::<靜態數據成員名>=<值>   
類的靜態數據成員有兩種訪問形式:   
<類對象名>.<靜態數據成員名> 或 <類類型名>::<靜態數據成員名>   
如果靜態數據成員的訪問權限允許的話(即 public 的成員),可在程序中,按上述格式來引用靜態數據成
員 ;   
靜態數據成員主要用在各個對象都有相同的某項屬性的時候。比如對於一個存款類,每個實例的利息都是
相同的。所以,應該把利息設為存款類的靜態數據成 員。這 有兩個好處,第一,不管定義多少個存款類
對象,利息數據成員都共享分配在全局數據區的內存,所以節省存儲空間。第二,一旦利息需要改變時,
只要改變一次, 則所有存款類對象的利息全改變過來了;   
同全局變量相比,使用靜態數據成員有兩個優勢:   
靜態數據成員沒有進入程序的全局名字空間,因此不存在與程序中其它全局名字沖突的可能性;   
可以實現信息隱藏。靜態數據成員可以是 private成員,而全局變量不能;   
2、靜態成員函數   
與靜態數據成員一樣,我們也可以創建一個靜態成員函數,它為類的全部服務而不是為某一個類的具體對
象服務。靜態成員函數與靜態數據成員一樣,都是類的 內部 實現,屬於類定義的一部分。 普通的成員函
數一般都隱含了一個this 指針,this 指針指向類的對象本身,因為普通成員函數總是具體的屬於某個類的
具體對象的。通常情況下,this 是缺省的。如函數fn()實際上是this->fn()。但是與普通函數相比,靜態成
員函數由於不是與任何的對象相聯系,因此它不具有this 指 針。從這個意義上講,它無法訪問屬於類對象
的非靜態數據成員,也無法訪問非靜態成員函數,它只能調用其余的靜態成員函數。   
關於靜態成員函數,可以總結為以下幾點:   
出現在類體外的函數定義不能指定關鍵字 static;   
靜態成員之間可以相互訪問,包括靜態成員函數訪問靜態數據成員和訪問靜態成員函數;   非靜態成員函數可以任意地訪問靜態成員函數和靜態數據成員;   
靜態成員函數不能訪問非靜態成員函數和非靜態數據成員;   
由於沒有this 指針的額外開銷,因此靜態成員函數與類的全局函數相比速度上會有少許的增長;   
調用靜態成員函數,可以用成員訪問操作符(.)和(->)為一個類的對象或指向類對象的指針調用靜態成員函
數,也可以直接使用如下格式:   
<類名>::<靜態成員函數名>(<參數表>)   
調用類的靜態成員函數。   
===============================================================================
================   
static 靜態變量聲明符。 在聲明它的程序塊,子程序塊或函數內部有效,值保持,在整個程序期間分配存
儲器空間,編譯器默認值0。   
是C++中很常用的修飾符,它被用來控制變量的存儲方式和可見性。   
2、為什么要引入static?   
函數內部定義的變量,在程序執行到它的定義處時,編譯器為它在棧上分配空間,大家知道,函數在棧上
分配的空間在此函數執行結束時會釋放掉,這樣就產生 了一個問題: 如果想將函數中此變量的值保存至下
一次調用時,如何實現? 最容易想到的方法是定義一個全局的變量,但定義為一個全局變量有許多缺點,
最明顯的缺點是破壞了此變量的訪問范圍(使得在此函數中定義的變量,不僅僅受此 函數控制)。   
3、什么時候用static?   
需要一個數據對象為整個類而非某個對象服務,同時又力求不破壞類的封裝性,即要求此成員隱藏在類的內
部,對外不可見。   
4、static 的內部機制:   
靜態數據成員要在程序一開始運行時就必須存在。因為函數在程序運行中被調用,所以靜態數據成員不能
在任何函數內分配空間和初始化。   
這樣,它的空間分配有三個可能的地方,一是作為類的外部接口的頭文件,那里有類聲明;二是類定義的
內部實現,那里有類的成員函數定義;三是應用程序的 main()函數前的全局數據聲明和定義處。   
靜態數據成員要實際地分配空間,故不能在類的聲明中定義(只能聲明數據成員)。類聲明只聲明一個類
的“尺寸和規格”,並不進行實際的內存分配,所以在 類聲明中寫成定義是錯誤的。它也不能在頭文件中類
聲明的外部定義,因為那會造成在多個使用該類的源文件中,對其重復定義。   
static 被引入以告知編譯器,將變量存儲在程序的靜態存儲區而非棧上空間,靜態   
數據成員按定義出現的先后順序依次初始化,注意靜態成員嵌套時,要保證所嵌套的成員已經初始化了。
消除時的順序是初始化的反順序。   
5、static 的優勢:   
可以節省內存,因為它是所有對象所公有的,因此,對多個對象來說,靜態數據成員只存儲一處,供所有
對象共用。靜態數據成員的值對每個對象都是一樣,但它的值是可以更新的。只要對靜態數據成員的值更
新一次,保證所有對象存取更新后的相同的值,這樣可以提高時間效率。   
6、引用靜態數據成員時,采用如下格式:   
<類名>::<靜態成員名>   
如果靜態數據成員的訪問權限允許的話(即public 的成員),可在程序中,按上述格式   
來引用靜態數據成員。   
7、注意事項:   
(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  用以生成唯一的標志。


免責聲明!

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



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