再探私有/公有靜態成員變數與私有靜態成員方法
阿新 • • 發佈:2019-02-09
問題1: 為什麼在類內的靜態成員定義後,要到類的外部在定義和初始化?
答:首先這句話就是錯的,在類內的靜態成員變數只是一定宣告,並沒有分配相應的記憶體空間;在類外,相當於定義加上初始化,如果只是定義,也是能夠編譯成功的,因為分配了記憶體。等價於全域性變數,但只屬於類。
問題2:為什麼類的靜態成員在類外部的定義只能一次?
答:好比全域性變數的多重定義
答:不能,解析不了。非靜態成員,不是一個特定的物件的,既沒有this指標,指向,根本找不到。
另外,任何變數都只進行一次初始化。區域性變數在程式塊結束時生存期就結束了,下次再呼叫這個程式塊時從原理上說宣告的是另一個變量了(分配到的地址也不一定一樣)。
PS:在不同編譯器的不同編譯情況時,實際的記憶體分割槽可能不同。例如TC的Small模式下堆和棧區是重合的,而Tiny模式下連靜態區域和動態區域都是重合的。問題3:私有的靜態成員變數如何初始化,訪問許可權還是私有麼? 答:顯然,也是在類的外部進行初始化,但是訪問許可權是存在的。比如不能在程式執行的過程中直接用類名加作用域來訪問此私有的靜態成員。需要通過類公有的外部介面來訪問,包括靜態與非靜態介面。 問題4:在程式執行過程中,其他類的物件改變靜態成員變數的值,那麼相應的在建立另一個物件時的靜態成員值會是初始化的值還是上一次改變的值? 答:是上一次改變的值,因為初始化是分配記憶體,賦初值。 問題5:類的非靜態成員函式中能訪問靜態成員變數麼? 答:是可以訪問的,前提是要對靜態的進行外部的初始化。如果為初始化,則會報錯,是連結錯誤,顯然在類內部只是宣告,並沒有在類的外部進行定義與初始化,未分配記憶體。 問題6:類的靜態成員函式中能訪問非靜態成員變數麼?
答:不能,解析不了。非靜態成員,不是一個特定的物件的,既沒有this指標,指向,根本找不到。
首先問題來自這個函式:
[cpp]int fun()
{ static int i=0;
i++;
return i;
}
當這個函式被反覆呼叫時,i的值是會一直加的,也就是靜態變數只被初始化了一次. 我對此產生了疑惑.不知道大家有沒有.當改為:
[cpp]int fun()
{
int i=0;
i++;
return i;
}
反覆呼叫時都返回的是1; 這個例子很明白,雖然i這個變數時同名的,但是地址是不一樣的,這是一個新的變數,因為在作用域後,原變數被銷燬了.接著建立一個新的變數. 那麼這裡我們就知道了一件事情:就是靜態變數是全域性的,和程式的生命週期是一樣的. 那麼原來的staic的i依然存在. 但是它的可訪問區域就只能是定義的作用域,而不一定能全域性訪問,這是全域性變數的一個差別.而靜態變數的必須初始化,如果沒有顯示初始化,則初始化為0 ,'0'或者其他. 初始化在程式第一次載入中開始.並設定了相應的標誌位! 所以當變數重複時,編譯器忽略了重複初始化的程式碼,到這裡就算是C++只能初始化一次的原因了!
作業系統在載入程式時會根據程式中的宣告部分為程式分配記憶體空間(這部分資料是由編譯器生成的)。程式所支配的記憶體空間分為兩大部分:靜態區域和動態區域(至於為什麼這樣區分涉及到硬體知識,建議LZ不要深究):動態區域用於儲存經常會變動的資料(動態區域又分為兩大部分:棧和堆,關於這兩個部分大家應該都很熟悉了);靜態區域(Java裡稱為永久區域)用於儲存不會經常變化的資料,例如程式的指令程式碼(C/C++裡就是各個函式編譯後得到的程式碼)、使用者型別(結構體、類)的宣告程式碼、全域性變數、靜態變數
有些例子提到用靜態變數來做遞迴的計數器,那只是為了說明靜態變數的特性。實際上不推薦這種用法,因為這樣會對程式效能造成輕微的影響。
靜態區域內的資料會在程式載入時進行初始化,生存期為程式執行的全部時間。