何時合成 Default Constructor?
C++ Standard:只有當編譯器**需要**時,才為無用戶聲明構造函數的類合成默認構造函數。合成構造函數僅執行編譯器所需的初始化,**不**初始化內建類型成員(如指針、整數)。
四種觸發合成的情況
- 含有默認構造函數的成員對象:需調用成員的默認構造。合成構造函數按聲明順序調用各成員默認構造。
- 繼承自有默認構造函數的基類:需調用基類默認構造。按繼承順序調用(多重繼承按基類聲明順序)。
- 類聲明虛函數:需初始化 vptr 指向正確 vtable。合成構造函數設置 vptr。
- 繼承鏈含虛基類:需初始化虛基類指針/偏移,確保運行期訪問正確。
合成構造函數的行為
- 只初始化上述四類「編譯器關心」的成員(基類子對象、類類型成員、vptr、虛基類指針)。
- **不**初始化內建類型數據成員(int, pointer, array 等)。這些初始化是程序員責任。
- 若用戶提供了**任意**構造函數,編譯器**不再**合成默認構造函數,而是擴張現有構造函數,在用戶代碼前插入必要的初始化調用。
初始化順序
- 基類構造函數(按繼承聲明順序)。
- 成員對象構造函數(按類中聲明順序)。
- 派生類自身構造函數體(用戶代碼)。
這保證了基類先於成員,成員先於派生類邏輯構造完成。
虛函數與 vptr 初始化
編譯器為每個含虛函數的類生成 vtable。構造函數中設置對象的 vptr 指向該類的 vtable。派生類構造時,先調用基類構造(設置基類 vptr),再設置派生類 vptr(覆蓋),最終對象 vptr 指向派生類 vtable。複製構造同理:必須顯式設置正確 vptr,不能位複製。
虛基類構造
虛基類在最派生類中只有一個實例。編譯器在構造函數中插入代碼,通過虛基類指針/偏移表定位並構造虛基類子對象。這在運行期完成,故破壞位逐次拷貝語意。
常見誤區
- 「任何無構造函數的類都會被合成默認構造函數」——**錯**,只有編譯器需要時才合成。
- 「合成默認構造函數會將所有成員初始化為 0/NULL」——**錯**,僅初始化編譯器需要的部分(基類、類成員、vptr、虛基類),內建類型**不**初始化。
總結
- 默認構造函數合成條件:四種「編譯器需要」情況之一。
- 合成內容:調用基類/成員默認構造、設置 vptr、修正虛基類指針。
- 初始化順序:基類 → 成員 → 自身。
- 用戶自定義構造函數會阻止默認構造函數合成,編譯器擴張用戶構造函數插入必要初始化。
- 內建類型成員初始化完全由程序員負責。