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

C++ 為什麼基類析構函數必須是虛函數:深度解析與反例

     編輯:關於C++

問題現象

class Base { public: ~Base() { cout << "Base dtor\n"; } };
class Derived : public Base { public: ~Derived() { cout << "Derived dtor\n"; } };

int main() {
    Base* ptr = new Derived();
    delete ptr; // 輸出僅 "Base dtor",Derived::~Derived() 未調用!
}

根本原因

  • 非虛析構:編譯器靜態綁定,根據指針類型(Base*)調用 Base::~Base()。
  • 虛析構:編譯器動態綁定,通過 vptr 查表調用對象真實類型(Derived)的析構函數,隨後自動調用基類析構,形成鏈式銷毀。

正確寫法

class Base {
public:
    virtual ~Base() { cout << "Base dtor\n"; } // 關鍵:virtual
};
class Derived : public Base {
public:
    ~Derived() override { cout << "Derived dtor\n"; }
};
// delete ptr 現在輸出:
// Derived dtor
// Base dtor

內存洩漏後果

若 Derived 持有資源(new 內存、文件句柄、鎖、socket),其析構函數負責釋放。不調用導致:

  • 堆內存洩漏(valgrind 可檢測)。
  • 文件描述符耗盡(EMFILE 錯誤)。
  • 死鎖(鎖未釋放)。

最佳實踐鐵律

  1. 凡是打算作為基類、可能被多態刪除的類,析構函數必須聲明為 virtual。
  2. 純虛析構也需提供定義:virtual ~Base() = 0 {}(C++ 允許純虛函數有函數體)。
  3. 用 override 標註派生類析構,防止簽名不匹配。
  4. 現代 C++ 優先用智能指針(unique_ptr/shared_ptr),自動管理生命周期,從源頭消除手動 delete 錯誤。

性能代價

  • 虛函數表增加對象大小(通常 8 字節指針)。
  • 間接調用極微小開銷(現代 CPU 分支預測幾乎消除)。
  • 相比資源洩漏風險,開銷可忽略不計。

總結

虛析構函數是 C++ 多態刪除的基石。面試必問、代碼審查必查、生產事故高發區。養成「寫類先寫 virtual ~Class()」的肌肉記憶。

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