C 靜態成員變數和靜態成員函式詳解

2021-10-03 20:21:02 字數 2725 閱讀 5666

類的靜態成員有兩種:靜態成員變數和靜態成員函式。靜態成員變數就是在定義時前面加了 static 關鍵字的成員變數;靜態成員函式就是在宣告時前面加了 static 關鍵字的成員函式。

下面的 crectangle 類就有兩個靜態成員變數和乙個靜態成員函式。

class

crectangle

;

普通成員變數每個物件有各自的乙份,而靜態成員變數只有乙份,被所有同類物件共享。

普通成員函式一定是作用在某個物件上的,而靜態成員函式並不具體作用在某個物件上。

訪問普通成員時,要通過物件名.成員名等方式,指明要訪問的成員變數是屬於哪個物件的,或要呼叫的成員函式作用於哪個物件;訪問靜態成員時,則可以通過類名::成員名的方式訪問,不需要指明被訪問的成員屬於哪個物件或作用於哪個物件。因此,甚至可以在還沒有任何物件生成時就訪問乙個類的靜態成員。

當然,非靜態成員的訪問方式(也即物件名.成員名)其實也適用於靜態成員,但效果和類名::成員名這種訪問方式沒有區別。

使用 sizeof 運算子計算物件所占用的儲存空間時,不會將靜態成員變數計算在內。對上面的 crectangle 類來說,sizeof(crectangle) 的值是 8。

靜態成員變數本質上是全域性變數。乙個類,哪怕乙個物件都不存在,其靜態成員變數也存在。靜態成員函式並不需要作用在某個具體的物件上,因此本質上是全域性函式。

設定靜態成員的目的,是為了將和某些類緊密相關的全域性變數和全域性函式寫到類裡面,形式上成為乙個整體。考慮乙個需要隨時知道矩形總數和總面積的圖形處理程式,當然可以用全域性變數來記錄這兩個值,但是將這兩個變數作為靜態成員封裝進類中,就更容易理解和維護。

例如下面的程式:

#include

using

namespace std;

class

crectangle

;crectangle::

crectangle

(int w_,

int h_)

crectangle::

~crectangle()

void crectangle::

printtotal()

int crectangle::totalnumber =0;

int crectangle::totalarea =0;

//必須在定義類的檔案中對靜態成員變數進行一次宣告 //或初始化,否則編譯能通過,鏈結不能通過

intmain()

程式的輸出是:

2, 13

2, 13

這個程式的基本思想是:crectangle 類只提供乙個建構函式,所有 crectangle 物件生成時都需要用這個建構函式初始化,因此在這個建構函式中增加矩形的總數和總面積的數值即可;而所有 crectangle 物件消亡時都會執行析構函式,所以在析構函式中減少矩形的總數和總面積的數值即可。

第 7 行和第 8 行的兩個成員變數用來記錄程式中所有矩形物件的總數和它們的總面積。這兩個值顯然不能由每個物件都維護乙份,而應該只有乙份。

雖然也可以用兩個全域性變數來存放這兩個值,但那樣就無法從形式上一眼看出這兩個全域性變數和 crectangle 類的緊密聯絡,也就看不出這兩個全域性變數會在哪些函式中被訪問。把它們寫成 crectangle 類的靜態成員變數,這個問題就迎刃而解了。

輸出矩形總數和總面積的函式 printtotal 沒有寫成全域性函式,而是寫成 crectangle 類的靜態成員函式,道理也是一樣的。

靜態成員變數必須在類定義的外面專門宣告,宣告時變數名前面加類名::,如第 29 行和第 30 行。宣告的同時可以初始化。如果沒有宣告,那麼程式編譯時雖然不會報錯,但是在鏈結(link)階段會報告「識別符號找不到」,不能生成.exe檔案。

第 36 行如果沒有注釋掉,編譯會出錯。因為 totalnumber 是私有成員,不能在成員函式外面訪問。

第 37 行和第 38 行的輸出結果相同,說明二者是等價的。

因為靜態成員函式不具體作用於某個物件,所以靜態成員函式內部不能訪問非靜態成員變數,也不能呼叫非靜態成員函式。假如上面程式中的 printtotal 函式如下編寫:

void crectangle::

printtotal()

其中訪問了非靜態成員變數 w,這是不允許的,編譯無法通過。因為如果用cretangle::printtotal();這種形式呼叫 printtotal 函式,那就無法解釋進入 printtotal 函式後,w 到底是屬於哪個物件的。

思考題:為什麼在靜態成員函式內不能呼叫非靜態成員函式?

在上面的程式中,crectangle 類的寫法表面看起來沒有什麼問題,實際上是有漏洞的。原因是,並非所有的 crectangle 物件生成時都會用程式中的那個建構函式初始化。如果使用該類的程式稍微複雜一些,包含以 crectangle 物件為引數的函式,或以 crectangle 物件為返回值的函式,或出現crectangle rl(r2);這樣的語句,那麼就有一些 crectangle 物件是用預設複製建構函式,而不是 crec:tangle(int w_, int h) 進行初始化的。這些物件生成時沒有增加 totalnumber 和 totalarea 的值,而消亡時卻減少了 totalnumber 和 totalarea 的 值,這顯然是有問題的。

解決辦法是為 crectangle 類編寫如下複製建構函式:

crectangle::

crectangle

(crectangle & r)

C 靜態成員變數和靜態成員函式

資料成員可以分靜態變數 非靜態變數兩種.靜態成員 靜態類中的成員加入static修飾符,即是靜態成員.可以直接使用類名 靜態成員名訪問此靜態成員,因為靜態成員存在於記憶體,非靜態成員需要例項化才會分配記憶體,所以靜態成員不能訪問非靜態的成員.因為靜態成員存在於記憶體,所以非靜態成員可以直接訪問類中靜...

C 靜態成員變數和靜態成員函式

資料成員可以分靜態變數 非靜態變數兩種.靜態成員 靜態類中的成員加入static修飾符,即是靜態成員.可以直接使用類名 靜態成員名訪問此靜態成員,因為靜態成員存在於記憶體,非靜態成員需要例項化才會分配記憶體,所以靜態成員不能訪問非靜態的成員.因為靜態成員存在於記憶體,所以非靜態成員可以直接訪問類中靜...

C 靜態成員變數和靜態成員函式

靜態成員變數和靜態資料成員並不屬於某乙個類物件,而是整個類,為所有物件共有,下面介紹 靜態成員變數和靜態資料成員的一些特徵 class a int tmain int argc,tchar argv 結果如下 1 class a const char a c b 可以通過作用域操作符,類的物件,引用...