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

深度探索 C++ 對象模型(五):複製構造函數與編譯器合成策略

     編輯:VC 教學

上一篇探討合成預設構造函數,本篇繼續深入複製構造函數的運作細節。

什麼是複製構造函數?

複製構造函數形式為 X(X&),參數為用戶自定義類型。當需要以一個對象內容初始化另一個同類對象時,編譯器會自動合成複製構造函數。主要三種情況:

  1. 對象初始化:ClassA a; ClassA b = a;
  2. 函數參數傳遞:以對象為參數傳入函數(按值傳遞)。
  3. 函數返回值:函數返回類對象實例。

複製構造函數的分類

同預設構造函數,複製構造函數也分為 trivial(平凡)與 nontrivial(非平凡)兩類。若類未聲明複製構造函數,編譯器會隱含聲明一個,視情況合成。

經典案例:淺拷貝導致的災難

class Word {
public:
    Word(const char*);
    ~Word() { delete [] str; }
private:
    int cnt;
    char *str;
};

// 使用情境
Word noun("lsmodel");
void foo() {
    Word verb = noun; // 災難發生
}

因 verb 與 noun 指向同一字串,verb 析構時釋放記憶體,導致 noun 成懸空指標。

解決方案:成員對象擁有複製構造函數

class String {
public:
    String(const char*);
    String(const String&); // 複製構造函數
    ~String();
};

class Word {
public:
    Word(const String&);
    ~Word();
private:
    int cnt;
    String str; // String 類對象
};

此時編譯器為 Word 合成複製構造函數,調用 str 的複製構造函數:

inline Word::Word(const Word& wd) {
    str.String::String(wd.str);
    cnt = wd.cnt;
}

四種不採用位元逐次拷貝的情況

  1. 類聲明了 explicit 複製構造函數。
  2. 類繼承自擁有 explicit 複製構造函數的基類。
  3. 類聲明了一個或多個虛函數。
  4. 類派生自含有虛擬基類的繼承鏈。

前兩種由程式設計師控制,後兩種由編譯器為了正確初始化 vptr 或虛擬基類指標/偏移量而合成複製構造函數,執行 memberwise 初始化與記憶體相關工作。

總結

當對象以另一對象為初值時,編譯器會視情況合成複製構造函數,確保正確初始化。理解這四種非位元拷貝情況,有助於避免淺拷貝導致的資源管理錯誤。

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