首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

深度探索 C++ 對象模型:建構子、複製建構子與虛擬機制解析(下)

     編輯:關於C++

預設建構子的合成時機與條件

編譯器僅在必要時才會合成預設建構子。若類別未宣告任何建構子,但符合特定條件,編譯器會生成一個 nontrivial(非平凡)的預設建構子,負責初始化基類子物件與成員類別物件。其他非靜態資料成員(如 int、指標)則不會被初始化。

四種觸發合成的情況

  1. 含有預設建構子的成員類別物件:若類別內含成員物件且該物件類別有預設建構子,編譯器會合成建構子,並按成員宣告順序呼叫各成員的預設建構子,置於使用者程式碼之前。
  2. 繼承自帶有預設建構子的基類:派生類別若無建構子,但基類有預設建構子,編譯器同樣會合成。基類建構子調用順序優於成員物件。
  3. 擁有虛擬函數的類別:為了初始化 vptr(虛擬函數表指標),編譯器必須合成預設建構子,將 vptr 設定為正確的虛擬表地址。
  4. 擁有虛擬基類的類別:為了讓透過指標/參考存取虛擬基類成為可能,編譯器需在物件中插入指向虛擬基類的指標,並由合成建構子初始化。

複製建構子的合成與位元複製語意

複製建構子僅在類別不呈現「位元複製語意」時才會被合成。以下四種情況會導致非位元複製語意:

  1. 成員物件類別宣告了複製建構子(明確或合成)。
  2. 基類存在複製建構子。
  3. 類別宣告虛擬函數(需正確複製 vptr,避免基類物件指向派生類虛擬表)。
  4. 繼承鏈中含有虛擬基類(需正確設定虛擬基類指標/偏移量)。

合成的複製建構子會遞迴執行 memberwise initialization,並插入必要的基類/成員複製建構子呼叫。

編譯器優化:命名回傳值優化 (NRVO) 與複製建構子省略

編譯器會優化物件回傳與初始化:

  • X xx0(1024); 單一建構子呼叫。
  • X xx1 = X(1024); 與 X xx2 = (X)1024; 理論上涉及暫時物件建立、複製建構、解構,但優化後可直接建構於目標物件,省略複製動作。

缺點:無法安全依賴複製建構子的副作用(如計數器),因執行次數不確定。

成員初始化列表:必要性與效能

下列情況必須使用成員初始化列表:

  1. 初始化 reference 成員。
  2. 初始化 const 成員。
  3. 呼叫帶參數的基類建構子。
  4. 呼叫帶參數的成員類別建構子。

使用初始化列表可避免「預設建構 → 暫時物件 → 指派 → 解構」的額外開銷,大幅提升效能。初始化順序依據類別內成員宣告順序,而非列表書寫順序,需特別留意相互依賴的初始化表達式。

程式碼範例:編譯器擴張後的建構子

// 使用者定義
Snow_White::Snow_White() : sneezy(1024) { mumble = 2048; }

// 編譯器擴張後
Snow_White::Snow_White() : sneezy(1024) {
    dopey.Dopey::Dopey();   // 成員物件建構
    sneezy.Sneezy::Sneezy();
    bashful.Bashful::Bashful();
    mumble = 2048;          // 使用者程式碼
}
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved