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

Effective C++ 條款 07:為多態基底類別宣告 virtual 解構函式

     編輯:關於C++

核心規則

凡帶有 virtual 函式的類別,其解構函式應宣告為 virtual。否則透過基底類別指標刪除衍生類別物件時,僅呼叫基底類別解構函式,導致衍生類別資源洩漏、行為未定義。

錯誤示範

class TimeKeeper {
public:
    TimeKeeper();
    ~TimeKeeper(); // 非 virtual
};
class AtomicClock : public TimeKeeper { /* ... */ };
class WaterClock  : public TimeKeeper { /* ... */ };

TimeKeeper* ptk = getTimeKeeper(); // 回傳衍生類別物件指標
delete ptk; // 僅呼叫 ~TimeKeeper(),衍生類別部分未銷毀 → 資源洩漏

正確做法

class TimeKeeper {
public:
    TimeKeeper();
    virtual ~TimeKeeper(); // virtual 解構函式
};

加上 virtual 後,delete ptk 會正確呼叫衍生類別解構函式(如 ~AtomicClock()),再呼叫基底類別解構函式,完整銷毀物件。

何時不需要 virtual 解構函式?

  • 類別非設計為基底類別(無 virtual 函式、無虛擬介面)。
  • 類別不打算被繼承(如 std::string、std::vector、STL 容器、boost::unordered_map 等)。
警告:繼承標準庫容器或無 virtual 解構函式的類別極易造成上述錯誤,請採用組合而非繼承。

虛擬解構函式的額外開銷

虛擬函式表(vtable)與指標(vptr)會增加每個物件大小(通常一個指標大小)與間接呼叫開銷。若類別無多態需求,避免宣告 virtual 解構函式可節省記憶體與提升效能。

純虛擬解構函式

若基底類別為抽象類別,可宣告純虛擬解構函式,但必須提供定義(因衍生類別解構時會呼叫基底版本):

class Base {
public:
    virtual ~Base() = 0; // 純虛擬
};
Base::~Base() {} // 必須定義

總結

  • 多態基底類別 → 必須有 virtual 解構函式。
  • 非多態類別、具體類別、STL 容器 → 不應有 virtual 解構函式。
  • 繼承標準庫容器是常見錯誤,請改用組合(has-a)。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved