2013-07-24 100 views
2

我想了解用於實現指向非靜態成員函數的指針的底層機制。我正在尋找一個類似於vtbl(用於多態的虛擬表)在全局中工作的答案,而不用擔心從編譯器到編譯器的細節可能不同。指向非靜態成員函數的指針的值

實施例:

#include <stdio.h> 

class A { 
public: 
    int i; 
    int j; 
    void foo(void) { }; 
}; 


int main() 
{ 
    int A::*ptr_j = &A::j; 
    void (A::*ptr_f)(void) = &A::foo; 
    printf("Foo::j pointer to data member %p\r\n", ptr_j); 
    printf("Foo::foo pointer to function member %p\r\n", ptr_f); 
} 

結果是

Foo::j指向數據成員0x4

Foo::foo函數指針構件0x804844c

選自「C++編程語言通過Stroustrup的」,

甲指針構件...更像是一個偏移量的結構或索引到一個數組...

對於數據成員,我知道指針對成員Foo::j或多或少等於offsetOf(Foo, j)。在我的主機環境中使用gcc編譯器時的值爲4,它與offsetOf(Foo, j)的值爲4.

對於函數成員,返回值爲0x804844c。這是一些地址屬於全局數據區

所以我的問題是(其中的類加載):

什麼是「對象」,也就是地址0x804844c

  1. 它不可能是一個簡單的offsetOf(),因爲這是一個很大的偏移。
  2. 它不能是vtbl的地址(或vtbl中的條目的地址),因爲我相信vbtl是與實例化對象關聯的實體,而不是類。
  3. 它不能是加載函數的實現代碼的地址。因爲在應用派生對象時,同一個指針可能會呈現多態。

那麼什麼是在地址0x804844c對象,什麼時候應用操作->*.*其在翻譯的指針到成員函數到實際的函數地址的作用是?

+2

在C++語言標準使用該術語的意義上,函數不是「對象」。請注意,成員函數通常作爲具有附加參數的常規函數​​來實現(該對象變成'this')。在那些實現中,它們不駐留在類實例本身中,而是與代碼段中的其他(免費)函數一起。 – dyp

+0

*「它不能是加載函數的實現代碼的地址,因爲當應用派生對象時,同一個指針可能會呈現多態。」 [這個答案](http://stackoverflow.com/a/1087671/420683) – dyp

回答

3

使用%p轉換說明符printf,不能打印指向成員對象的值。它們不一定是常規指針。 %p說明符需要一個void *值。嚴格來說,你甚至不能用%p打印一個常規函數指針,因爲這需要將函數指針轉換爲void *

指針到成員類型不一定適合可以容納地址的一個機器字。它們可以是具有多個字段的數據結構。

我相信vbtl是一個與實例化對象關聯的實體,而不是類。

這是不正確的。虛擬表是靜態結構,實例只指向它們。給定類的所有實例都共享一個指向同一個表的指針。

指向非靜態成員函數的指針在一個方面比較簡單,因爲它不必處理類實例中任意數據成員的偏移量。然而,指向非靜態成員函數的指針由於需要支持虛擬函數而變得複雜,並且由於通過像這樣的指針調用的代碼不知道或不在意它是調用虛函數還是非虛函數。

指向成員函數的一種實現策略涉及thunks:編譯器生成的代碼片斷,它們執行正確的邏輯以正確的方式進行調用。然後指向成員的指針可指向thunk。 thunk知道在this對象中的哪個位置查找vtable指針,以及vtable中的哪個偏移量是最終要調用的函數。