C++ 虛函數(shù)列表(虛函數(shù)表,vtable)
虛函數(shù)列表(通常稱為虛函數(shù)表或vtable)是C++實現(xiàn)運行時多態(tài)(動態(tài)綁定)的關(guān)鍵機制。下面詳細(xì)介紹虛函數(shù)表的相關(guān)內(nèi)容:
1. 虛函數(shù)表的基本概念
- 虛函數(shù)表(vtable):每個包含虛函數(shù)的類都有一個虛函數(shù)表,表中存儲了該類所有虛函數(shù)的地址
- 虛指針(vptr):每個對象內(nèi)部有一個隱藏的指針指向該類的虛函數(shù)表
- 動態(tài)綁定:通過虛函數(shù)表在運行時確定調(diào)用哪個函數(shù)實現(xiàn)
2. 虛函數(shù)表的結(jié)構(gòu)
對于這樣一個類層次結(jié)構(gòu):
class Base { public: virtual void func1() {} virtual void func2() {} }; class Derived : public Base { public: void func1() override {} virtual void func3() {} };
虛函數(shù)表大致如下:
Base類的vtable:
[0] Base::func1() 的地址 [1] Base::func2() 的地址
Derived類的vtable:
[0] Derived::func1() 的地址 // 覆蓋了Base的func1 [1] Base::func2() 的地址 // 繼承自Base [2] Derived::func3() 的地址 // 新增虛函數(shù)
3. 虛函數(shù)表的工作原理
Base* ptr = new Derived(); ptr->func1(); // 實際調(diào)用Derived::func1()
調(diào)用過程:
- 通過對象的vptr找到vtable
- 在vtable中找到func1對應(yīng)的條目
- 跳轉(zhuǎn)到該地址執(zhí)行
4. 虛函數(shù)表的特點
- 每個類一個vtable:不是每個對象一個,同類的對象共享同一個vtable
- 編譯時創(chuàng)建:虛函數(shù)表在編譯時生成,存放在程序的只讀數(shù)據(jù)段
- 繼承關(guān)系: 派生類繼承基類的vtable覆蓋的虛函數(shù)會替換對應(yīng)位置的函數(shù)指針新增的虛函數(shù)會追加到vtable末尾
5. 虛函數(shù)表的開銷
- 空間開銷:每個包含虛函數(shù)的類有一個vtable每個對象多一個vptr(通常4或8字節(jié))
- 時間開銷:虛函數(shù)調(diào)用需要間接尋址(多一次指針解引用)通常無法內(nèi)聯(lián)虛函數(shù)
6. 查看虛函數(shù)表的方法(GCC)
可以使用-fdump-class-hierarchy
選項查看虛函數(shù)表布局:
g++ -fdump-class-hierarchy your_file.cpp
7. 虛函數(shù)表的實際應(yīng)用
- 動態(tài)多態(tài)的基礎(chǔ)
- **RTTI(運行時類型識別)**的實現(xiàn)依賴虛函數(shù)表
- dynamic_cast的實現(xiàn)也依賴虛函數(shù)表
8. 注意事項
- 構(gòu)造函數(shù)不能是虛函數(shù)(因為此時vptr尚未初始化)
- 析構(gòu)函數(shù)通常應(yīng)該是虛函數(shù)(特別是基類)
- 虛函數(shù)表機制是編譯器實現(xiàn)的,C++標(biāo)準(zhǔn)只規(guī)定行為,不規(guī)定實現(xiàn)方式
虛函數(shù)表是理解C++多態(tài)底層機制的關(guān)鍵,了解它有助于編寫更高效的C++代碼和調(diào)試復(fù)雜的繼承問題。