《深度探索c 記憶體模型》讀書筆記 (二)

2021-10-24 21:34:17 字數 1673 閱讀 6964

總結c++ 編譯器會在人意想不到的地方做一些隱式操作。例如,只含有乙個引數的建構函式,會被當做型別轉換運算子。而關鍵字explict就是為了阻止這一機制。

c++ 編譯器會在需要的時候自動生成預設建構函式。

如果乙個類沒有任何的建構函式,但是它有乙個物件成員,這個物件成員有乙個預設建構函式。那麼編譯器將會為這個類生成乙個預設建構函式。但是這個生成的時機會是在這個類被呼叫的時候。

如果有兩個檔案中都呼叫了這個類,那麼預設建構函式將可能會被生成兩次。如何避免這種衝突呢?解決方法是把合成的建構函式內聯(inline, 乙個內聯函式有靜態鏈結 static linkage)。如果建構函式太複雜,不適合內聯,那麼就會合成乙個顯式的非內聯靜態實體(explicit noinline static)。

例如:

class foo ;

class bar ;

// 編譯器將會為bar合成預設建構函式,初始化foo成員。但是並不會初始化str成員!!!

如果乙個類foo有自己定義的建構函式(預設的,或者帶有引數的),並且這個類還有乙個或者多個類成員。那麼編譯器將會保證這些類成員的建構函式在foo的建構函式中至少被呼叫一次。這些成員的構造順序與它們在class中的宣告順序一致。

類似的,如果乙個沒有建構函式的派生類繼承自乙個帶有預設建構函式的基類。那麼編譯器將會為這個派生類生成預設建構函式。在這個生成的建構函式中按照宣告的順序呼叫基類的建構函式。

如果派生類有建構函式,但是沒有預設建構函式。編譯器將會為現有的建構函式中安插呼叫基類建構函式的**,但是並不會生成乙個新的預設建構函式。

如果這個派生類同時有類成員(這些類成員有預設建構函式)。那麼編譯器將會在基類建構函式的**後面安插呼叫資料成員建構函式的**。

有以下兩種情況會生成預設建構函式

在編譯期間,編譯器會做兩件事情:

生成乙個虛函式表

為每乙個物件新增乙個額外的虛函式表指標。

對於類所定義的每乙個建構函式,編譯器將會安插一些**,為虛表指標賦初值。帶有乙個虛基類的類編譯器會使乙個虛基類在派生類中的位置 在執行期間所決定??

例如

class x;

class a :public virtual x ;

class b :public virtual x ;

class c :public a, public b ;

​// 無法在編譯時期決定i的位置(偏移?)

void foo(const a *pa)

​int main ()

編譯器的一種可能的實現方式為:

在每乙個派生類的虛基類中安插乙個指標。經由引用或者指標來訪問乙個虛基類的功能都可以由這個指標來實現。

例如:

// 可能的轉換操作

void

foo(

const a *pa)

在編譯器合成的預設建構函式中,會為那些有預設建構函式的成員或者基類呼叫其預設建構函式。而那些其他的非靜態資料成員,例如整數,指標等都不會被初始化,需要類的設計者(就是程式設計師了)來做這些操作。

新手一般會有兩個誤解

任何類如果沒有定義預設建構函式,那麼就會被合成出乙個來。

編譯器合成的預設建構函式會明確設定類中的每乙個資料成員初始值。

這兩個沒有乙個是真的!!!

《深度探索c 記憶體模型》讀書筆記 (四)

成員們的初始化隊伍 如果有這樣的定義 x x0 x x1 x0 x x2 x0 x x3 x x0 都將會導致x的拷貝建構函式被呼叫。如果函式定義如下 void foo x x0 x xx foo xx x那麼呼叫foo函式時,將會呼叫x類的拷貝建構函式,生成乙個臨時物件,如下 x temp tem...

《深度探索c 記憶體模型》讀書筆記 (五)

乙個類物件所佔空間的大小主要受以下三個因素影響 語言本身的額外負擔,虛繼承,虛函式 編譯器對特殊情況的優化處理 空的 對齊 乙個沒有資料成員的普通物件 沒有虛基類和虛繼承 所占用的空間也不是0個位元組。而是1個位元組,這個是被編譯器安插進去的,為了使這個物件在記憶體中保持獨一無二的位址。然而,當這個...

《深度探索C 物件模型》讀書筆記(5)

純虛函式 在設計抽象基類時,需要注意以下幾點 1 不要將destructor宣告為pure virtual function 如果將destructor宣告為pure virtual function,則設計者一定得定義它。因為每乙個derived class destructor會被編譯器加以擴充...