目錄
- 一、默認構造函數(Default Constructor)
- 二、普通構造函數(General Constructor)
- 三、拷貝構造函數(Copy Constructor)
- 四、移動構造函數(Move Constructor,C++11)
- 五、委托構造函數(Delegating Constructor,C++11)
- 六、析構函數(Destructor)
- 七、綜合示例:完整類設計
- 八、總結對比
- 九、最佳實踐
C++中的構造函數和析構函數是面向對象編程的核心機制,它們管理對象的生命周期和資源。本文結合C++11及后續標準,深入解析默認構造函數、普通構造函數、拷貝構造函數、移動構造函數、委托構造函數及析構函數的核心特性和應用場景。
一、默認構造函數(Default Constructor)
定義:沒有參數或所有參數均有默認值的構造函數。若未顯式定義任何構造函數,編譯器會自動生成一個空實現的默認構造函數。
特點:
- 用于初始化對象默認狀態
- 自動生成的條件:類中無任何構造函數時
- 可手動禁用或顯式聲明(= default或= delete)
示例:
class MyClass {
public:MyClass() = default; // 顯式聲明默認構造函數MyClass(int x = 0) : value(x) {} // 帶默認參數的構造函數
private:int value;
};
注意事項:
- 若存在其他構造函數,編譯器不再自動生成默認構造函數
- 對于含有內置類型成員的對象,默認構造函數不會初始化成員變量(可能產生隨機值)
二、普通構造函數(General Constructor)
定義:帶參數的構造函數,用于初始化對象的特定狀態。支持重載,可通過不同參數組合創建對象。
特點:
- 通過初始化列表高效初始化成員變量
- 支持多態初始化,例如std::string(“Hello”)
示例:
class Student {
public:Student(int id, const string& name) : m_id(id), m_name(name) {} // 初始化列表
private:int m_id;string m_name;
};
應用場景:
- 需要明確初始化邏輯時(如數據庫連接需指定IP和端口)
- 避免成員變量未初始化導致的未定義行為
三、拷貝構造函數(Copy Constructor)
定義:通過已有對象初始化新對象,形式為ClassName(const ClassName& other)。默認實現為淺拷貝,需手動處理指針成員。
調用時機:
- 對象作為函數參數傳遞(值傳遞)
- 函數返回對象時
- 顯式拷貝初始化(MyClass obj2 = obj1;)
深淺拷貝對比:
// 淺拷貝(默認危險行為)
class ShallowCopy {
public:int* data;ShallowCopy(int val) { data = new int(val); }~ShallowCopy() { delete data; } // 潛在雙重釋放
};// 深拷貝(安全實現)
class DeepCopy {
public:int* data;DeepCopy(const DeepCopy& other) {data = new int(*other.data); // 重新分配內存}
};
四、移動構造函數(Move Constructor,C++11)
定義:通過右值引用(&&)轉移資源所有權,避免不必要的拷貝開銷。
核心機制:
- 竊取臨時對象或即將銷毀對象的資源
- 將原對象指針置空避免重復釋放
- 需標記為noexcept以支持STL容器優化
示例:
class String {
public:// 移動構造函數String(String&& other) noexcept : data(other.data), size(other.size) {other.data = nullptr; // 轉移后置空原指針}
private:char* data;size_t size;
};
性能優勢:
- 減少動態內存分配次數
- 在vector::push_back等操作中避免深拷貝
五、委托構造函數(Delegating Constructor,C++11)
定義:通過初始化列表調用同類其他構造函數,減少代碼冗余。
規則:
- 必須通過初始化列表委托
- 禁止循環委托(如A委托B,B又委托A)
- 可結合參數默認值實現靈活初始化
示例:
class Rectangle {
public:// 主構造函數Rectangle(int w, int h) : width(w), height(h) {}// 委托構造:正方形初始化Rectangle(int size) : Rectangle(size, size) {}// 委托構造:默認初始化Rectangle() : Rectangle(0, 0) {}
};
六、析構函數(Destructor)
定義:對象生命周期結束時自動調用,用于釋放資源,形式為~ClassName()。
關鍵特性:
- 不可重載(每個類唯一)
- 虛析構函數支持多態刪除(virtual ~Base())
- 默認析構函數不處理動態內存
資源管理示例:
class FileHandler {
public:FileHandler(const string& path) { file = fopen(path.c_str(), "r"); }~FileHandler() { if(file) fclose(file); // 確保資源釋放}
private:FILE* file;
};
注意事項:
- 含有指針成員的類必須自定義析構函數
- 析構順序:派生類→成員對象→基類
七、綜合示例:完整類設計
class AdvancedClass {
public:// 默認構造AdvancedClass() : data(nullptr), size(0) {}// 普通構造AdvancedClass(int s) : size(s), data(new int[s]{}) {}// 拷貝構造(深拷貝)AdvancedClass(const AdvancedClass& other) : size(other.size), data(new int[other.size]) {std::copy(other.data, other.data + size, data);}// 移動構造AdvancedClass(AdvancedClass&& other) noexcept : data(other.data), size(other.size) {other.data = nullptr;}// 委托構造AdvancedClass(int a, int b) : AdvancedClass(2) {data[0] = a; data[1] = b;}// 析構函數~AdvancedClass() { delete[] data; }private:int* data;int size;
};
八、總結對比
函數類型 | 語法特征 | 核心作用 | 性能影響 |
---|---|---|---|
默認構造函數 | ClassName() | 基礎初始化 | 低 |
普通構造函數 | 帶參數 | 定制化初始化 | 中 |
拷貝構造函數 | const ClassName& | 對象復制(深/淺拷貝) | 可能高(深拷貝) |
移動構造函數 | ClassName&& | 資源轉移 | 高 |
委托構造函數 | 構造器鏈式調用 | 代碼復用 | 無 |
析構函數 | ~ClassName() | 資源釋放 | 關鍵 |
九、最佳實踐
- Rule of Five:若自定義拷貝構造/賦值、移動構造/賦值、析構函數中的任意一個,建議顯式定義全部五個。
- RAII原則:通過構造函數獲取資源,析構函數釋放資源。
- 移動語義優先:對臨時對象使用std::move觸發移動語義。
- 委托構造優化:減少重復初始化代碼。
通過合理運用這些特性,可構建高效、安全的C++對象模型,尤其在資源管理、高性能計算等場景中體現關鍵價值。