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

C++ 虛函數深度解析:多態實現、虛析構、純虛函數與抽象類

     編輯:關於C++

虛函數是 C++ 運行時多態的核心機制。通過 virtual 關鍵字聲明,配合基類指針/引用指向派生類對象,實現「同一接口,不同行為」。本文從底層實現原理到工程最佳實踐,全方位剖析虛函數體系。

1. 虛函數基本機制

class Base {
public:
    virtual void fun() { cout << "Base::fun()\n"; }
};
class Derived : public Base {
public:
    void fun() override { cout << "Derived::fun()\n"; } // override 可選但推薦
};

int main() {
    Derived d;
    Base* pb = &d;
    pb->fun(); // 輸出 "Derived::fun()" —— 動態綁定
}
  • 無 virtual 時:靜態綁定,調用基類版本。
  • 有 virtual 時:動態綁定,通過 虛表 (vtable) 查找實際對象類型對應的函數地址。

2. 虛函數實現原理:虛表指針 (vptr) + 虛表 (vtable)

  • 含虛函數的類,編譯器生成靜態 vtable(函數指針數組)。
  • 每個對象隱含 vptr 指向其類的 vtable。
  • 派生類繼承基類 vtable,覆蓋函數則替換對應槽位。
  • pb->fun() 編譯為:(*pb->vptr[slot])(pb)。

3. 多層繼承與虛函數傳遞

class A { virtual void f(); };
class B : public A { void f() override; }; // 自動成為虛函數
class C : public B { void f() override; };

C c; B* pb = &c; pb->f(); // 調用 C::f()

規則:基類虛函數 → 所有派生類同名函數自動為虛函數,無論是否寫 virtual。

4. 虛析構函數:安全刪除派生類對象

class Base {
public:
    virtual ~Base() { cout << "~Base()\n"; } // 必須虛析構
};
class Derived : public Base {
public:
    ~Derived() { cout << "~Derived()\n"; }
};

Base* p = new Derived;
delete p; // 輸出 ~Derived() -> ~Base()
  • 無 virtual 時 delete pb 僅調用 ~Base(),導致派生類資源洩漏。
  • 規則:只要類可能作為基類被繼承,析構函數必須聲明為 virtual。

5. 純虛函數與抽象類


class Shape {
public:
    virtual double area() = 0; // 純虛函數:無實現,強制派生類實現
    virtual ~Shape() = default;
};
class Circle : public Shape {
    double r;
public:
    Circle(double r) : r(r) {}
    double area() override { return 3.14159 * r * r; }
};
// Shape s; // 錯誤:抽象類不能實例化
Shape* s = new Circle(1.0); // 正確:指向具體派生類
  • = 0 僅為語法標記,非賦值操作。
  • 含純虛函數的類為抽象類,不可實例化,僅作接口規範。
  • 派生類未實現所有純虛函數 → 仍為抽象類。

6. 關鍵禁忌與最佳實踐

場景錯誤做法正確做法
構造/析構中調用虛函數動態綁定失效,調用當前類版本避免調用;或用非虛接口模式 (NVI)
普通函數聲明 virtual編譯錯誤虛函數只能是非靜態成員函數
純虛函數提供實現語法合法但罕見通常不提供;若需默認實現可在類外定義
基類指針 delete 派生對象基類析構非 virtual基類析構必須 virtual

7. 內存佈局圖解

無virtual調用基類 有virtual調用派生類 多層繼承調用最底層 非虛析構僅調用基類 虛析構正確調用鏈 抽象類實例化報錯 調用純虛函數報錯 派生類未實現純虛函數報錯

總結

  1. virtual 啟用動態綁定,實現運行時多態。
  2. 虛析構是多態類的強制要求(RAII 安全)。
  3. 純虛函數定義接口契約,構建抽象類體系。
  4. override (C++11) 防止拼寫錯誤導致隱藏而非覆蓋。
  5. 理解 vptr/vtable 有助於診斷切片、多重繼承菱形等疑難問題。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved