天天看點

C/C++中的static關鍵字的總結 C/C++中static的2種設計和5種使用方法 面向過程設計中的static 面向對象的static關鍵字(類中的static關鍵字)

面向過程程式設計中的static和面向對象程式設計中的static

具體應用的話,又涉及靜态變量和靜态函數兩類

前者應用于普通變量(變量又分局部變量和全部變量)和函數,不涉及類;後者主要說明static在類中的作用。

是以結構關系如下,那麼我們具體來分析

面向過程程式設計中的static

靜态局部變量,成為靜态局部變量(擁有記憶功能和全局存儲權限)

靜态全局變量(限制對應全局變量被被其他檔案調用)

靜态函數

面向對象程式設計中的static。

靜态成員變量

靜态成員函數

在c/c++中, 局部變量按照存儲形式可分為三種<code>auto</code>, <code>static</code>, <code>register</code>

關于extern 首先,extern和static完全不同,extern不能定義一個變量,extern表示的是“已經存在一個變量,但是不在目前的編譯單元内,需要在其他編譯單元中尋找。

與<code>auto</code>類型(普通)局部變量相比, <code>static</code>局部變量有三點不同

存儲空間配置設定不同

auto類型配置設定在棧上, 屬于動态存儲類别, 占動态存儲區空間, 函數調用結束後自動釋放, 而static配置設定在靜态存儲區, 在程式整個運作期間都不釋放. 兩者之間的作用域相同, 但生存期不同.

static局部變量在所處子產品在初次運作時進行初始化工作, 且隻操作一次

對于局部靜态變量, 如果不賦初值, 編譯期會自動賦初值0或空字元, 而auto類型的初值是不确定的. (對于c++中的class對象例外, class的對象執行個體如果不初始化, 則會自動調用預設構造函數, 不管是否是static類型)

在全局變量前,加上關鍵字<code>static</code>,該變量就被定義成為一個靜态全局變量。我們先舉一個靜态全局變量的例子,如下:

靜态全局變量有以下特點:

* 該變量在全局資料區配置設定記憶體;

* 未經初始化的靜态全局變量會被程式自動初始化為0(自動變量的值是随機的,除非它被顯式初始化);

* 靜态全局變量在聲明它的整個檔案都是可見的,而在檔案之外是不可見的; 

靜态變量都在全局資料區配置設定記憶體,包括後面将要提到的靜态局部變量。對于一個完整的程式,在記憶體中的分布情況如下圖: 

記憶體布局

代碼區

全局資料區

堆區

棧區

一般程式的由c-malloc/c++new産生的動态資料存放在堆區,函數内部的自動變量存放在棧區。

自動變量一般會随着函數的退出而釋放空間,靜态資料(即使是函數内部的靜态局部變量)也存放在全局資料區。

全局資料區的資料并不會因為函數的退出而釋放空間。

代碼中将 “static int n; //定義靜态全局變量”改為“int n; //定義全局變量”。

程式照樣正常運作。

的确,定義全局變量就可以實作變量在檔案中的共享,但定義靜态全局變量還有以下好處:

靜态全局變量不能被其它檔案所用;

其它檔案中可以定義相同名字的變量,不會發生沖突;

您可以将上述示例代碼改為如下:

編譯并運作,您就會發現上述代碼可以分别通過編譯,但運作時出現錯誤。

試着将 “static int n; //定義靜态全局變量”改為 “int n; //定義全局變量”

再次編譯運作程式,細心體會“全局變量”和”靜态全局變量”的差別。

在局部變量前,加上關鍵字<code>static</code>,該變量就被定義成為一個靜态局部變量。 我們先舉一個靜态局部變量的例子

通常,在函數體内定義了一個變量,每當程式運作到該語句時都會給該局部變量配置設定棧記憶體。但随着程式退出函數體,系統就會收回棧記憶體,局部變量也相應失效。但有時候我們需要在兩次調用之間對變量的值進行儲存。通常的想法是定義一個全局變量來實作。但這樣一來,變量已經不再屬于函數本身了,不再僅受函數的控制,給程式的維護帶來不便。

靜态局部變量正好可以解決這個問題。

靜态局部變量儲存在全局資料區,而不是儲存在棧中,每次的值保持到下一次調用,直到下次賦新值。

靜态局部變量有以下特點:

該變量在全局資料區配置設定記憶體;

靜态局部變量在程式執行到該對象的聲明處時被首次初始化,即以後的函數調用不再進行初始化;

靜态局部變量一般在聲明處初始化,如果沒有顯式初始化,會被程式自動初始化為0;

它始終駐留在全局資料區,直到程式運作結束。但其作用域為局部作用域,當定義它的函數或語句塊結束時,其作用域随之結束;

按存儲區域分,全局變量、靜态全局變量和靜态局部變量都存放在記憶體的靜态存儲區域,局部變量存放在記憶體的棧區。

按作用域分, 全局變量在整個工程檔案内都有效;靜态全局變量隻在定義它的檔案内有效;靜态局部變量隻在定義它的函數内有效,隻是程式僅配置設定一次記憶體,函數傳回後,該變量不會消失;局部變量在定義它的函數内有效,但是函數傳回後失效。

全局變量(外部變量)的說明之前再冠以static就構成了靜态的全局變量。全局變量本身就是靜态存儲方式,靜态全局變量當然也是靜态存儲方式。這兩者在存儲方式上并無不同。這兩者的差別雖在于非靜态全局變量的作用域是整個源程式,當一個源程式由多個源檔案組成時,非靜态的全局變量在各個源檔案中都是有效的。 而靜态全局變量則限制了其作用域,即隻在定義該變量的源檔案内有效,在同一源程式的其它源檔案中不能使用它。由于靜态全局變量的作用域局限于一個源檔案内,隻能為該源檔案内的函數公用,是以可以避免在其它源檔案中引起錯誤。

從以上分析可以看出, 把局部變量改變為靜态變量後是改變了它的存儲方式即改變了它的生存期。把全局變量改變為靜态變量後是改變了它的作用域, 限制了它的使用範圍。

static 函數與普通函數作用域不同。僅在本檔案。隻在目前源檔案中使用的函數應該說明為内部函數(static),内部函數應該在目前源檔案中說明和定義。對于可在目前源檔案以外使用的函數,應該在一個頭檔案中說明,要使用這些函數的源檔案要包含這個頭檔案

static全局變量與普通的全局變量有什麼差別:static全局變量隻初始化一次,防止在其他檔案單元中被引用;

static局部變量和普通局部變量有什麼差別:static局部變量隻被初始化一次,下一次依據上一次結果值;

static函數與普通函數有什麼差別:static函數在記憶體中隻有一份,普通函數在每個被調用中維持一份拷貝

全局變量和靜态變量如果沒有手工初始化,則由編譯器初始化為0。局部變量的值不可知。

在函數的傳回類型前加上static關鍵字,函數即被定義為靜态函數。

函數前加static使得函數成為靜态函數。但此處“static”的含義不是指存儲方式,而是指對函數的作用域僅局限于本檔案(是以又稱内部函數)。

使用内部函數的好處是:不同的人編寫不同的函數時,不用擔心自己定義的函數,是否會與其它檔案中的函數同名。

靜态函數與普通函數不同,它隻能在聲明它的檔案當中可見,不能被其它檔案使用。

定義靜态函數的好處:

* 靜态函數不能被其它檔案所用;

* 其它檔案中可以定義相同名字的函數,不會發生沖突;

在類内資料成員的聲明前加上關鍵字static,該資料成員就是類内的靜态資料成員。

可以看出,靜态資料成員有以下特點:

* 對于非靜态資料成員,每個類對象都有自己的拷貝。而靜态資料成員被當作是類的成員。無論這個類的對象被定義了多少個,靜态資料成員在程式中也隻有一份拷貝,由該類型的所有對象共享通路。也就是說,靜态資料成員是該類的所有對象所共有的。對該類的多個對象來說,靜态資料成員隻配置設定一次記憶體,供所有對象共用。是以,靜态資料成員的值對每個對象都是一樣的,它的值可以更新;

靜态資料成員存儲在全局資料區。靜态資料成員定義時要配置設定空間,是以不能在類聲明中定義。在example 5中,語句int myclass::sum=0;是定義靜态資料成員;

靜态資料成員和普通資料成員一樣遵從public,protected,private通路規則;

因為靜态資料成員在全局資料區配置設定記憶體,屬于本類的所有對象共享,是以,它不屬于特定的類對象,在沒有産生類對象時其作用域就可見,即在沒有産生類的執行個體時,我們就可以操作它;

靜态資料成員初始化與一般資料成員初始化不同。靜态資料成員初始化的格式為:

<資料類型><類名>::<靜态資料成員名>=<值>

類的靜态資料成員有兩種通路形式:

<類對象名>.<靜态資料成員名> 或 <類類型名>::<靜态資料成員名>

如果靜态資料成員的通路權限允許的話(即public的成員),可在程式中,按上述格式來引用靜态資料成員 ;

* 靜态資料成員主要用在各個對象都有相同的某項屬性的時候。比如對于一個存款類,每個執行個體的利息都是相同的。是以,應該把利息設為存款類的靜态資料成員。這有兩個好處,第一,不管定義多少個存款類對象,利息資料成員都共享配置設定在全局資料區的記憶體,是以節省存儲空間。第二,一旦利息需要改變時,隻要改變一次,則所有存款類對象的利息全改變過來了;

同全局變量相比,使用靜态資料成員有兩個優勢:

靜态資料成員沒有進入程式的全局名字空間,是以不存在與程式中其它全局名字沖突的可能性;

可以實作資訊隐藏。靜态資料成員可以是private成員,而全局變量不能;

  與靜态資料成員一樣,我們也可以建立一個靜态成員函數,它為類的全部服務而不是為某一個類的具體對象服務。靜态成員函數與靜态資料成員一樣,都是類的内部實作,屬于類定義的一部分。普通的成員函數一般都隐含了一個this指針,this指針指向類的對象本身,因為普通成員函數總是具體的屬于某個類的具體對象的。通常情況下,this是預設的。如函數fn()實際上是this-&gt;fn()。但是與普通函數相比,靜态成員函數由于不是與任何的對象相聯系,是以它不具有this指針。從這個意義上講,它無法通路屬于類對象的非靜态資料成員,也無法通路非靜态成員函數,它隻能調用其餘的靜态成員函數。下面舉個靜态成員函數的例子。

關于靜态成員函數,可以總結為以下幾點:

* 出現在類體外的函數定義不能指定關鍵字static;

靜态成員之間可以互相通路,包括靜态成員函數通路靜态資料成員和通路靜态成員函數;

非靜态成員函數可以任意地通路靜态成員函數和靜态資料成員;

靜态成員函數不能通路非靜态成員函數和非靜态資料成員;

由于沒有this指針的額外開銷,是以靜态成員函數與類的全局函數相比速度上會有少許的增長;

調用靜态成員函數,可以用成員通路操作符(.)和(-&gt;)為一個類的對象或指向類對象的指針調用靜态成員函數,也可以直接使用如下格式:

<類名>::<靜态成員函數名>(<參數表>)

調用類的靜态成員函數。

轉載:http://blog.csdn.net/gatieme/article/details/50900505

繼續閱讀