class Base { public: Base(); ~Base(); ... };
class Derived : public Base { ... };
Base* p = new Derived;
delete p; // 危險!若 Base::~Base() 非虛,只調用 Base 析構,Derived 析構不被調用 → 資源洩漏
凡是擁有虛函數的類(即設計為多態基類),其析構函數必須聲明為 virtual。
vptr 指向 vtable,析構同樣需動態分發。delete p 通過 vptr 找到正確的析構函數入口,保證「最深層派生類 → 基類」順序調用。std::string、std::vector)不應加虛析構,否則每個對象多佔指針大小內存,違背「不為不用的特性付費」原則。當類沒有任何純虛成員函數,但仍想強制其為抽象類(不可實例化),只能將析構函數聲明為純虛:
class Test {
public:
virtual ~Test() = 0; // 純虛析構
};
// 必須在類外提供定義,否則鏈接報錯 "undefined reference to Test::~Test()"
Test::~Test() { } // 空實現即可
原因:派生類析構時會隱式調用基類析構,編譯器在派生類析構函數中插入 Base::~Base() 調用指令,鏈接階段必須找到符號。
派生類構造: 基類構造 → 成員構造 → 派生類構造體 派生類析構: 派生類析構體 → 成員析構 → 基類析構(遞歸向上)
虛析構保證此順序在運行時通過 vtable 正確執行。
| 場景 | 析構函數聲明 | 說明 |
|---|---|---|
| 多態基類(有虛函數) | virtual ~Base() | 必須,防止 delete 基類指針洩漏 |
| 非多態具體類 | ~Concrete() | 非虛,零開銷 |
| 強制抽象類(無其他純虛) | virtual ~Abstract() = 0; + 類外定義 | 純虛析構需定義,否則鏈接失敗 |
| 接口類(全純虛) | virtual ~Interface() = default; | C++11 默認實現,簡潔明確 |
虛析構不是可選裝飾,是多態類型系統的基石。 記住三句口訣:
1. 有 virtual 就要 virtual ~()。
2. 純虛 ~() 必須寫定義。
3. 非多態類別加 virtual ~() 會多佔 8 字節(64位),得不償失。