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

C++ 構造函數與析構函數深度解析:調用時機、初始化列表、虛析構、常見陷阱

     編輯:關於C++

構造函數

核心職責

  1. 分配空間:為非靜態數據成員分配內存(非指針成員由編譯器自動處理;指針成員需程序員在構造函數體中 new)。
  2. 初始化成員:賦值初始化(普通成員)或初始化列表初始化(const、引用、類對象成員、無默認構造的成員)。

調用時機

  • 對象定義時:A a(10);、A a = 10;(單參數構造,非 explicit)。
  • new 創建時:A* p = new A(10);。
  • 臨時對象、函數參數傳值、返回值(可能被優化)。

語法規則

  • 同類名,無返回類型(連 void 都不能寫)。
  • 可重載、可帶默認參數、可 inline、可 explicit(防隱式轉換)。

初始化列表(Member Initializer List)

class A {
    int x;
    int& ref;
    const float pi;
public:
    A(int x1) : ref(x), pi(3.14f) {  // 必須用初始化列表
        x = x1;  // 普通成員可在函數體賦值
    }
};
  • 初始化順序:按成員在類中聲明順序,與列表書寫順序無關。
  • 數組成員不能用初始化列表,需在函數體循環賦值或 memcpy。
  • 基類構造函數也在初始化列表調用:Derived(int x) : Base(x), member(x) {}。

析構函數

核心職責

  1. 釋放資源:指針成員 delete、關閉文件句柄、釋放鎖、關閉網絡連接等。
  2. 非指針成員由編譯器自動析構(調用其析構函數)。

調用時機

  • 棧上對象離開作用域:函數結束、塊結束。
  • delete 堆上對象:delete p;(單個)、delete[] p;(數組)。
  • 臨時對象生命週期結束。

語法規則

  • 名為 ~ClassName(),無參數、無返回類型、不可重載、不可帶默認參數。
  • 基類析構函數必須聲明為 virtual,否則刪除基類指針指向派生對象時僅調用基類析構,導致資源洩漏。

經典陷阱:聲明未定義導致鏈接錯誤

class AAA {
public:
    AAA(); ~AAA();  // 僅聲明
};
// AAA() {}  // 定義在 cpp 中
// ~AAA() {} // 忘記定義!

int main() {
    AAA a;        // 編譯通過,鏈接錯誤:undefined reference to AAA::~AAA()
    AAA* p = new AAA();
    // delete p; // 這行若執行也會鏈接錯誤
}

原因:編譯器自動生成默認構造/析構/拷貝/賦值,但用戶一旦聲明任意一個,編譯器就不再自動生成任何一個。必須全部定義(哪怕是空函數體)。

new/delete 配對原則

分配方式釋放方式備註
new Tdelete p調用 1 次構造、1 次析構
new T[N]delete[] p調用 N 次構造、N 次析構(需記錄 N)
new Tdelete[] p未定義行為(可能崩潰)
new T[N]delete p未定義行為(僅析構第 1 個,內存釋放錯誤)

內置類型(int 等)無析構函數,new int[10] 配 delete p 偶爾能跑通,但極其危險,嚴禁依賴。

總結

  1. 構造:分配 + 初始化;析構:清理 + 釋放。
  2. 初始化列表用於 const、引用、基類、類對象成員。
  3. 基類析構必須 virtual。
  4. 聲明即定義:寫了聲明必須提供定義(可在類內內聯、類外、cpp 文件)。
  5. new/delete、new[]/delete[] 嚴格配對。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved