🧩 一圖看懂:虛函數 vs 純虛函數
特性 | 虛函數(Virtual) | 純虛函數(Pure Virtual) |
---|---|---|
語法 | virtual void foo(); | virtual void foo() = 0; |
是否必須實現 | ? 必須在類中實現 | ? 不在基類實現,派生類必須實現 |
是否可被重寫 | ? 可重寫(override) | ? 必須被重寫(override) |
用途 | 支持運行時多態,可選重寫 | 強制派生類必須重寫,實現接口規范 |
是否構成抽象類 | ? 不一定 | ? 是抽象類,不能實例化 |
? 虛函數(virtual
)
-
語法:
virtual void speak();
-
作用:支持 運行時多態
-
特性:
-
有默認實現
-
可以被子類覆蓋
-
必須是非靜態成員函數
-
-
使用場景:需要在子類中覆蓋行為(但不是強制)
? 純虛函數(= 0
)
-
語法:
virtual void speak() = 0;
-
作用:創建接口函數,強制子類必須實現
-
特性:
-
沒有默認實現
-
子類 必須重寫,否則也是抽象類
-
所在類稱為 抽象類,不能被實例化
-
-
用途:面向接口編程、設計規范
class Animal {
public:
? ? virtual void speak() = 0; // 純虛函數
};
? 靜態成員函數(static
)
-
屬于類本身,而不是對象
-
? 不能是虛函數,因為沒有 this 指針
-
無法訪問非靜態成員(因為不依賴對象)
class A {
public:
??static void sayHello(); // 和對象無關
};
🧠 三、抽象類(包含純虛函數的類)
-
語法:類中至少一個函數是
virtual void foo() = 0;
-
特點:
-
不能被實例化
-
派生類必須實現純虛函數,才可以實例化
-
通常作為接口使用,規范子類的行為
-
📌 四、虛函數工作原理:虛函數表(vtable)
-
編譯器為類創建一張虛函數表
-
對象內部有個隱藏指針指向這個表(vptr)
-
當你調用虛函數時,實際會通過 vtable 找到正確的函數地址 ? 實現多態
🔑 小結:口訣記憶版
項目 | 口訣 |
---|---|
const 指針 | 左定值,右定向,const 修飾不變量 |
虛函數 | 支持多態,可選覆蓋 |
純虛函數 | 沒有實現,強制子類實現,是接口 |
抽象類 | 有純虛函數,不可實例化,只能繼承 |
靜態函數 | 類級函數,不能訪問對象成員,不能是虛函數 |
多態原則 | 通過指針/引用訪問虛函數,才會發生運行時多態 |
析構函數 | 如果類有虛函數,析構函數也應為虛函數,防止內存泄漏 |
詳情請見:C++ 虛函數和純虛函數的區別 | 菜鳥教程