關於為什麼類的靜態成員變數不能立即初始化

2021-09-30 04:46:38 字數 1328 閱讀 9092

我們都知道**1是錯誤的,今天我去追究其原因。當然有些地方屬於個人理解,有所紕漏,請不吝惜指正。

// test.h

**1

當我們寫下面的**時,而沒有在cpp檔案裡給出定義,就會出現無法解析的外部符號錯誤。這是因為"static int a;"是對變數a的宣告。我們都知道,類例項化時,編譯器分配記憶體給成員變數,也就是說,當產生類的例項時定義成員變數,但是對於靜態成員變數呢?

**2

我們假設靜態成員變數和其他成員變數沒有區別,也是在類例項化時編譯器賦予記憶體,那麼如下**:

**3

就定義了乙個區域性物件,那麼自然而然的,當這個函式執行完畢的時候,物件t析構,靜態成員變數a的空間被釋放掉。那就根本無法達到類共享靜態成員變數的目的。所以有如下結論:靜態成員變數在類例項化之前就已經存在了,並且分配了記憶體,它交由類專屬使用(這是靠static的內部鏈結屬性實現的),類無法控制它何時被分配記憶體,何時釋放。我們不妨把它理解為乙個在類中宣告,專屬於類的全域性變數,它的鏈結屬性為內部鏈結。

談完靜態成員變數的性質以後,讓我們來討論一下為什麼靜態成員變數不能立即初始化,也就是像**1那樣去做。

假設我們可以將靜態成員變數立即初始化,那麼**3展開:

這裡面的靜態成員變數不再是乙個宣告,而是定義,當函式fun執行到"t.a = 3;"時,不會再把a當成為乙個外部符號,不會把它放入未解決符號表中。a首先被賦值為0,然後被修改為3。再看以下**:

這裡面是同樣的道理,"static int a = 0;"不再是乙個宣告,而是定義,當函式fun執行到"t.a += 3;"時,不會把a當成乙個外部符號,不會把它放入未解決符號表中。所以在本編譯單元裡尋找t.a,發現值為0,那麼"t.a += 3;"的執行結果是t.a的值為3,而不是6,沒有類的物件共享靜態成員變數的目的。

有人可能會問為什麼"const static int a = 5;"這樣的語句放在類的定義裡可以呢,如下面**:

那是因為const使其成為了常量,不會擔心上面所述的問題。但是,這樣的定義,雖然值是不會改變,會不會造成無法共享靜態成員變數a呢?因為在包含該類的標頭檔案的cpp裡面,將#include "test.h"擴充套件後,都有這麼一句"const int a = 5;"這豈不是在不同的地方定義了靜態成員變數a麼?也就是說,當我們要取a的位址的時候,會不會發現在包含test.h的各個cpp中,取得a的位址不同?

請看下面**:

該段**經過反彙編後:

可以看到int b = t.a;的彙編語句是:

00411433  mov         dword ptr [b],5

這說明編譯器已經對const int static a = 5;優化了。注意:只有靜態常量整形資料成員才可以立即初始化。

為什麼靜態成員不能訪問非靜態成員

註明本文章 首先static的成員是在類載入的時候初始化的,jvm的classloader的載入,首次主動使用載入,而非static的成員是在建立物件的時候,即new 操作的時候才初始化的 先後順序是先載入,才能初始化,那麼載入的時候初始化static的成員,此時非static的成員還沒有被載入必然...

為什麼靜態成員不能訪問非靜態成員

不使用static修飾的成員是非靜態成員 例項成員 物件成員 只能通過物件 例項 來呼叫。而靜態方法中不能使用this引用,即沒有非靜態物件,所以直接不能呼叫非靜態成員。如果確實需要在靜態方法中訪問普通成員,只能重新建立乙個物件 首先static的成員是在類載入的時候初始化的,jvm的classlo...

非靜態內部類為什麼不能有靜態成員變數和靜態方法。

首先要明白以下三點 1 static型別的屬性和方法,在類載入的時候就會存在於記憶體中。2 要想使用某個類的static屬性和方法,那麼這個類必須要載入到虛擬機器 中。3 非靜態內部類並不隨外部類一起載入,只有在例項化外部類之後才會載入。現在考慮這個情況 在外部類並沒有例項化,內部類還沒有載入,這時...