《深度探索c++記憶體模型》讀書筆記 (二)
前言
c++ 編譯器會在人意想不到的地方做一些隱式操作。例如,只含有一個引數的建構函式,會被當做型別轉換運算子。而關鍵字explict就是為了阻止這一機制。
預設建構函式
c++ 編譯器會在需要的時候自動生成預設建構函式。
帶有預設建構函式的類物件成員
如果一個類沒有任何的建構函式,但是它有一個物件成員,這個物件成員有一個預設建構函式。那麼編譯器將會為這個類生成一個預設建構函式。但是這個生成的時機會是在這個類被呼叫的時候。
如果有兩個檔案中都呼叫了這個類,那麼預設建構函式將可能會被生成兩次。如何避免這種衝突呢?解決方法是把合成的建構函式內聯(inline, 一個行內函數有靜態連結 static linkage)。如果建構函式太複雜,不適合內聯,那麼就會合成一個顯式的非內聯靜態實體(explicit noinline static)。
例如:
class Foo {
public:
Foo()
};
class Bar {
Foo foo;
char *str;
};
// 編譯器將會為Bar合成預設建構函式,初始化foo成員。但是並不會初始化str成員!!!
如果一個類Foo有自己定義的建構函式(預設的,或者帶有引數的),並且這個類還有一個或者多個類成員。那麼編譯器將會保證這些類成員的建構函式在Foo的建構函式中至少被呼叫一次。這些成員的構造順序與它們在class中的宣告順序一致。
帶預設建構函式的基類
類似的,如果一個沒有建構函式的派生類繼承自一個帶有預設建構函式的基類。那麼編譯器將會為這個派生類生成預設建構函式。在這個生成的建構函式中按照宣告的順序呼叫基類的建構函式。
如果派生類有建構函式,但是沒有預設建構函式。編譯器將會為現有的建構函式中安插呼叫基類建構函式的程式碼,但是並不會生成一個新的預設建構函式。
如果這個派生類同時有類成員(這些類成員有預設建構函式)。那麼編譯器將會在基類建構函式的程式碼後面安插呼叫資料成員建構函式的程式碼。
帶有虛擬函式的類
有以下兩種情況會生成預設建構函式
- 類宣告或者繼承一個虛擬函式
- 類派生自一個繼承串鏈,其中有一個或者更多的虛基類(virtual base class)
在編譯期間,編譯器會做兩件事情:
- 生成一個虛擬函式表
- 為每一個物件新增一個額外的虛擬函式表指標。
對於類所定義的每一個建構函式,編譯器將會安插一些程式碼,為虛表指標賦初值。帶有一個虛基類的類編譯器會使一個虛基類在派生類中的位置 在執行期間所決定??
例如
class X{public: int i};
class A :public virtual X {public: int j;};
class B :public virtual X {public: double d;};
class C :public A, public B {public: int k;};
// 無法在編譯時期決定i的位置(偏移?)
void foo(const A *pa) {
pa->i = 1024;
}
int main ()
{
foo (new C);
foo (new A);
...
}
編譯器的一種可能的實現方式為:
在每一個派生類的虛基類中安插一個指標。經由引用或者指標來存取一個虛基類的功能都可以由這個指標來實現。
例如:
// 可能的轉換操作
void foo(const A *pa) {
pa->__vbcX->i = 1024;
}
總結
在編譯器合成的預設建構函式中,會為那些有預設建構函式的成員或者基類呼叫其預設建構函式。而那些其他的非靜態資料成員,例如整數,指標等都不會被初始化,需要類的設計者(就是程式設計師了)來做這些操作。
新手一般會有兩個誤解:
- 任何類如果沒有定義預設建構函式,那麼就會被合成出一個來。
- 編譯器合成的預設建構函式會明確設定類中的每一個資料成員初始值。
這兩個沒有一個是真的!!!
相關文章
- 《深度探索C++物件模型》讀書筆記C++物件模型筆記
- 深度解讀《深度探索C++物件模型》之C++物件的記憶體佈局C++物件模型記憶體
- C++記憶體模型實踐探索C++記憶體模型
- Java記憶體模型深度解讀Java記憶體模型
- JVM讀書筆記之記憶體管理JVM筆記記憶體
- 探索Java記憶體模型Java記憶體模型
- 讀書筆記】《PostgreSQL指南-內幕探索》-2.程式和記憶體架構筆記SQL記憶體架構
- Java記憶體模型FAQ(二) 其他語言,像C++,也有記憶體模型嗎?Java記憶體模型C++
- 讀書筆記2-記憶體優化篇筆記記憶體優化
- JVM讀書筆記之java記憶體結構JVM筆記Java記憶體
- C++讀書筆記:字串C++筆記字串
- 《Effective C++》讀書筆記C++筆記
- JVM讀書筆記之垃圾收集與記憶體分配JVM筆記記憶體
- Java 記憶體模型 JMM 深度解析Java記憶體模型
- Java記憶體模型深度解析:鎖Java記憶體模型
- [讀書筆記]軟體估算-估算方法(二)筆記
- 《Windows核心情景分析》讀書筆記:windows記憶體管理Windows筆記記憶體
- 深入理解JVM讀書筆記二: 垃圾收集器與記憶體分配策略JVM筆記記憶體
- 深入理解JVM讀書筆記五: Java記憶體模型與Volatile關鍵字JVM筆記Java記憶體模型
- The Great Gatsby讀書筆記(二)筆記
- TIJ讀書筆記(二) (轉)筆記
- 【Mysql】讀書筆記之--innodb_buffer_pool記憶體的管理MySql筆記記憶體
- 讀書筆記:深入解析oracle-第5章 記憶體管理筆記Oracle記憶體
- Java記憶體模型深度解析:重排序Java記憶體模型排序
- Java記憶體模型深度解析:volatileJava記憶體模型
- Java記憶體模型深度解析:finalJava記憶體模型
- Java記憶體模型深度解析:總結Java記憶體模型
- 深度學習讀書筆記之RBM深度學習筆記
- C語言深度剖析——讀書筆記C語言筆記
- 深度解讀《深度探索C++物件模型》之C++虛擬函式實現分析(二)C++物件模型函式
- 深入理解JVM讀書筆記一: Java記憶體區域與記憶體溢位異常JVM筆記Java記憶體溢位
- Java記憶體模型深度解析:基礎部分Java記憶體模型
- c++11 記憶體模型解讀C++記憶體模型
- 記憶體模型記憶體模型
- 《深入java虛擬機器》讀書筆記之Java記憶體區域Java虛擬機筆記記憶體
- Objective-C高階程式設計讀書筆記之記憶體管理Object程式設計筆記記憶體
- 讀書筆記...筆記
- 讀書筆記筆記