首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 更多程式設計知識

C++ 類別建構函式完整解析:從預設到移動語意

     編輯:更多程式設計知識

前言

建構函式是 C++ 物件生命週期的起點,負責初始化資料成員、配置資源。本文系統整理六大類建構函式,搭配 Complex 複數類別範例,說明呼叫時機、參數形式與常見陷阱,並補充 C++11 移動建構與 explicit 關鍵字的現代用法。

一、建構函式的核心職責

當物件被建立時,編譯器自動呼叫建構函式完成:

  1. 為資料成員配置記憶體
  2. 依初始化清單或函式主體賦予初值
  3. 建立類別不變式
class Counter {
public:
    Counter() : m_value(0) {}   // 初始化清單寫法(推薦)
private:
    int m_value;
};
Counter c1;   // m_value 自動為 0

二、六大建構函式分類與範例

類型特徵呼叫情境備註
預設建構無參數或全有預設值T obj; new T()若未自訂任何建構函式,編譯器會隱式產生空函式
一般建構(多載)參數列表不同T obj(arg); T obj{arg};可定義多個,支援不同初始化方式
複製建構T(const T&)以現有物件初始化新物件淺拷貝風險,含指標成員時必須深拷貝
移動建構 (C++11)T(T&&) noexcept從右值(暫時物件)轉移資源避免深拷貝開銷,標準庫容器大量依賴
轉換建構單一非參考參數隱式型別轉換 T obj = 3.14;加 explicit 禁止隱式轉換
委派建構 (C++11)在初始化清單呼叫同類別其他建構函式減少重複程式碼T() : T(default_arg) {}

三、Complex 完整實作示範

#include <iostream>
using namespace std;

class Complex {
    double m_real, m_imag;
public:
    // 1. 預設建構
    Complex() : m_real(0), m_imag(0) { cout << "Default ctor\n"; }

    // 2. 一般建構
    Complex(double r, double i) : m_real(r), m_imag(i) { cout << "General ctor\n"; }

    // 3. 複製建構
    Complex(const Complex& rhs) : m_real(rhs.m_real), m_imag(rhs.m_imag) { cout << "Copy ctor\n"; }

    // 4. 移動建構
    Complex(Complex&& rhs) noexcept : m_real(rhs.m_real), m_imag(rhs.m_imag) {
        rhs.m_real = rhs.m_imag = 0;
        cout << "Move ctor\n";
    }

    // 5. 轉換建構(加 explicit 防隱式轉換)
    explicit Complex(double r) : m_real(r), m_imag(0) { cout << "Converting ctor\n"; }

    // 6. 複製指派運算子
    Complex& operator=(const Complex& rhs) {
        if (this != &rhs) { m_real = rhs.m_real; m_imag = rhs.m_imag; }
        cout << "Copy assign\n"; return *this;
    }

    // 7. 移動指派運算子
    Complex& operator=(Complex&& rhs) noexcept {
        if (this != &rhs) { m_real = rhs.m_real; m_imag = rhs.m_imag; rhs.m_real = rhs.m_imag = 0; }
        cout << "Move assign\n"; return *this;
    }

    friend ostream& operator<<(ostream& os, const Complex& c) {
        return os << '(' << c.m_real << ", " << c.m_imag << ')';
    }
};

int main() {
    Complex c1;                 // Default
    Complex c2(1.0, 2.5);       // General
    Complex c3 = c2;            // Copy ctor (複製初始化)
    Complex c4; c4 = c2;        // Copy assign (指派)
    Complex c5 = Complex(3.0);  // Converting ctor (需 explicit 則寫 Complex c5(3.0))
    Complex c6 = std::move(c2); // Move ctor
    c1 = std::move(c3);         // Move assign
    cout << c1 << c4 << c5 << c6 << endl;
}

四、關鍵觀念釐清

初始化 vs 指派

  • Complex c3 = c2; → 複製初始化,呼叫複製建構函式
  • Complex c4; c4 = c2; → 預設建構 + 複製指派

淺拷貝與深拷貝

若類別含原始指標 int* p,預設複製建構只複製指標值,導致雙重釋放。必須自訂:

Complex(const Complex& rhs) : m_real(rhs.m_real), m_imag(rhs.m_imag) {
    p = new int(*rhs.p);   // 深拷貝
}

explicit 的防禦性設計

void func(Complex c); 
func(3.14);          // 若無 explicit,隱式轉換通過編譯,易造成誤用
func(Complex(3.14)); // 加上 explicit 後,必須顯式建構

五、最佳實務摘要

  1. 優先使用 初始化清單 而非函式主體賦值
  2. 含資源管理(指標、檔案控制代碼、Socket)的類別,必須實作「五大函式」:解構函式、複製建構、複製指派、移動建構、移動指派
  3. 單參數建構函式預設加 explicit,除非確有隱式轉換需求
  4. 移動操作標記 noexcept,讓標準庫容器在重新配置記憶體時優先使用移動而非複製
  5. 善用 = default / = delete 明確表達意圖

結語

建構函式是 C++ 物件模型的基石,掌握其六種形式與資源管理規則,能寫出高效、安全的現代 C++ 程式碼。建議配合 C++ Core Guidelines 定期審視類別設計。

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