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

C++ 類別成員初始化深度解析:初始化列表 vs 建構函數體賦值

     編輯:關於C++

兩種初始化寫法比較


// 寫法一:建構函數體內賦值
class CSomeClass {
    int x, y;
public:
    CSomeClass() { x = 0; y = 1; }
};

// 寫法二:成員初始化列表
class CSomeClass {
    int x, y;
public:
    CSomeClass() : x(0), y(1) { }
}

何時「必須」使用初始化列表

1. 成員為無預設建構函數的類別型別


class CMember {
public:
    explicit CMember(int val) : data(val) {} // 唯一建構函數需參數
private:
    int data;
};

class CMyClass {
    CMember m_member; // 無預設建構函數
public:
    CMyClass() : m_member(42) {} // 必須在初始化列表傳參
};

若在建構函數體賦值,編譯器會先嘗試呼叫 CMember() 預設建構函數 → 編譯錯誤。

2. const 成員與參考成員


class CExample {
    const int MAX_SIZE;
    int& refData;
public:
    CExample(int& r) : MAX_SIZE(100), refData(r) {} // 唯一合法位置
};

C++ 規定 const 物件與參考只能初始化,不能賦值。

效能考量:避免雙重建構/賦值

以 MFC CString 為例:


class CMyClass {
    CString m_str;
public:
    // 寫法 A:建構函數體賦值 → 呼叫預設建構 + operator=
    CMyClass() { m_str = _T("Hello"); }

    // 寫法 B:初始化列表 → 直接呼叫 CString(LPCTSTR) 建構函數
    CMyClass() : m_str(_T("Hello")) { }
};
  • 寫法 A:CString() 預設建構 → operator=(LPCTSTR) 賦值 = 兩次函數呼叫,可能觸發兩次記憶體配置。
  • 寫法 B:CString(LPCTSTR) 直接建構 = 一次函數呼叫,效率更高。

對於擁有昂貴建構/賦值操作的大型類別 (配置大量記憶體、開啟檔案控制碼等),初始化列表能顯著減少資源浪費。

內建型別與 POD:無效能差異

對於 int、long、指標等無建構函數的型別,兩種寫法編譯後機器碼幾乎相同,僅有一次移動/賦值指令。此時可依團隊編碼風格選擇。

初始化順序陷阱:宣告順序決定初始化順序


class CMyClass {
    int m_x;
    int m_y;
public:
    CMyClass(int i) : m_y(i), m_x(m_y) {} // 危險!
};

成員初始化順序遵循類別定義中的宣告順序,而非初始化列表中的書寫順序。上例中 m_x 先初始化,但此時 m_y 尚未初始化 → m_x 得到不定值。

避免錯誤的兩大原則

  1. 成員宣告順序 = 邏輯初始化依賴順序 (先被依賴的先宣告)。
  2. 初始化列表書寫順序 = 成員宣告順序 (編譯器會對不匹配發出警告)。

實務建議總結

情境建議做法理由
成員為類別型別、const、參考必須用初始化列表語法強制要求
成員為昂貴建構/賦值的類別 (CString, std::vector, 含大量資源的類別)優先用初始化列表避免雙重建構/賦值,提升效能
成員為內建型別、指標、簡單 POD任選一致風格無效能差異;建構函數體賦值便於對齊、註釋、memset 等
多成員相互依賴初始化調整宣告順序 + 列表順序一致確保正確初始化序列

現代 C++ (C++11 後) 新選擇:預設成員初始化


class ModernClass {
    int x = 0;           // C++11 非靜態資料成員初始化
    int y = 1;
    std::string name;    // 預設建構為空字串
public:
    ModernClass() = default; // 編譯器自動產生正確建構函數
    ModernClass(int a, int b) : x(a), y(b) {} // 仍可覆寫
};

此語法將預設值直接寫在成員宣告處,簡潔且不易出錯,配合 = default 讓編譯器生成最佳建構函數,是現代 C++ 推薦做法。

結語

成員初始化列表非單純語法糖,而是 C++ 物件模型的核心機制。理解「初始化」與「賦值」的本質差異、掌握初始化順序規則、根據成員型別特性選擇恰當策略,是撰寫高效、正確、可維護 C++ 程式碼的關鍵功力。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved