2012-06-07 38 views
5

據我所知,對象中的virtual函數指針表的位置依賴於編譯器。
將這個指針放在對象的開頭還是末尾,反之亦然?虛擬功能表指針在對象中的位置

+0

[從Objdump實用工具中檢索vptr(指向虛擬表指針VTABLE的指針)的可能重複?](http://stackoverflow.com/questions/10549311/retrieving-vptrpointer-to-virtual-table-aka-vtablefrom- the-objdump-utility) – iammilind

回答

7

虛擬函數表的存在與編譯器相關(但是所有編譯器都是這樣),並且該位置也沒有強制要求......在所有編譯器中我知道細節,vptr存儲在對象的開始處。原因是它提供了一個統一的位置。考慮一個類層次結構:

struct base { 
    T data; 
    virtual void f(); 
}; 
struct derived : base { 
    T1 data; 
    virtual void g(); 
}; 

如果vptr的是存儲在對象的末尾,那麼這將是後sizeof(T)字節爲完全型base的對象。現在,當您有完整類型derived的對象時,base子對象的佈局必須與完整的base對象的佈局兼容,因此vptr仍然必須在對象內部爲sizeof(T)字節,該字節位於對象的某處derived對象的中間(從開始,sizeof(T1)結束之前)。因此它不再位於對象的

此外,給定一個this指針,虛擬調用需要間接通過vtable,這基本上是取消引用vptr,添加一個偏移量並跳轉到存儲在那裏的內存位置。如果vptr存儲在對象的末尾,則對於每個虛擬呼叫,在解引用vptr之前,會額外增加this

+0

理論上你可以在基類子對象和完整對象的末尾都有vptr。這會有一定的意義:對於不出現在「Base」中的虛擬函數有'Derived' vptr。但每個對象的開銷並不那麼好。 – MSalters

+0

很棒的解釋! –

4

是的,它完全依賴於實施。
對於簡單的繼承層次結構,它位於對象的開始位置,但對於複雜的層次結構則不會。
無論如何,您編寫的任何源代碼不應該依賴於它所在的位置,實際上,您編寫的任何代碼都不應該依賴於虛擬表或虛擬表指針的存在。
C++標準沒有要求通過虛擬表和指針來實現虛擬調度,實現可以使用其他實現方法自由地實現它。但是,所有主流編譯器都通過表指針機制來實現這一點,需要注意的重要一點是它們可能在指針所在位置的確切實現方式上有所不同。