2013-03-22 33 views
8

我正在嘗試使用C++來理解類/結構和它們各自的對象是如何在內存中佈局的,我理解類/結構的每個字段都是它們各自對象的偏移量(所以我可以有一個成員變量指針)。成員函數的存儲位置在哪裏?

我不明白爲什麼,即使我可以有成員函數指針,下面的代碼無法正常工作:

struct mystruct 
{ 
    void function() 
    { 
     cout << "hello world"; 
    } 
    int c; 
}; 

int main() 
{ 
    unsigned int offset_from_start_structure = (unsigned int)(&((mystruct*)0)->c); 
    unsigned int offset_from_start_structure2 = (unsigned int)(&((mystruct*)0)->function); // ERROR - error C2276: '&' : illegal operation on bound member function expression 



    return 0; 
} 

我的問題是:爲什麼行

unsigned int offset_from_start_structure = (unsigned int)(&((mystruct*)0)->c); 

編譯並返回從結構起始處的「c」字段的偏移量和行

unsigned int offset_from_start_structure2 = (unsigned int)(&((mystruct*)0)->function); 

d甚至不能編譯?

+5

成員函數不存儲在對象中(爲什麼會這樣?它們對於該類型的所有對象都是相同的)。如果它有幫助(也許不是;也許它只會增加混淆,但我會嘗試)成員函數指針是*不*指針。 – 2013-03-22 14:10:39

+0

你在期望內存中的_function_的內容是什麼?函數不是數據。他們是代碼。 – 2013-03-22 14:12:41

+1

「我正在嘗試使用C++來理解類/結構和它們各自的對象是如何在內存中佈局的」實現細節,與語言無關 – 2013-03-22 14:12:43

回答

15

成員函數或指向它們的指針不存儲在該對象。 (virtual函數通常通過存儲在一個表中的指針調用,而對象只有一個指針指向)這會浪費大量的內存。它們通常存儲在代碼存儲器部分,並且是編譯器已知的。對象(*this)通常作爲不可見的參數傳遞,因此函數知道調用哪個對象時要進行操作。

所以,通俗地說,你必須

0x10001000 void A::foo 
.......... {code for A::foo} 

push a; 
call A::foo (0x10001000) 
pop a; 

其中a是你在叫foo的對象。

+0

謝謝您的澄清,但爲什麼不行?它應該至少返回一個固定的地址 – 2013-03-22 14:17:15

+0

@JohnnyPauling不,它不應該。 '&((mystruct *)0) - > c'是未定義的行爲,你不能只取消引用空指針。谷歌的'指向成員函數'的指針,你會找到正確的做法。 – 2013-03-22 14:18:53

+0

我不認爲這是一個未定義的行爲,它每次我調用它時會返回c字段的偏移量,它也適用於其他連續字段,所以我想知道爲什麼它不能用函數 – 2013-03-22 14:20:26

2

成員函數指針實際上並不存儲在對象中:沒有必要。 C++標準沒有詳細說明如何虛擬函數將被實現,但虛擬成員函數的常見做法是每個對象都包含一個指向函數指針表的指針;這個指針叫做vtable pointer

您可能試圖獲得Stanley Lippman的「Inside the C++ object model」

或者,您可能會試圖在我的當前主頁網站消失之前,試圖抓住我的舊pointers tutorial,曾經引用維基百科的指針文章。


關於第二個問題,爲什麼服用p->memberFunc地址,使編譯器嗆一點,清楚表達沒有類型,它只是一個語法實體,你可以申請一個參數列表,以便調用該函數。

要機智,

struct S 
{ 
    void foo() {} 
}; 

#include <iostream> 
#include <typeinfo> 
using namespace std; 
int main() 
{ 
    S* p = 0; 
    typeid(&p->foo); 
} 

彙編:

 
[W:\dev\test] 
>g++ foo.cpp 
foo.cpp: In function 'int main()': 
foo.cpp:12:17: error: ISO C++ forbids taking the address of a bound member function to form a pointer to member function. Say '&S::foo' [-fpermissive] 
foo.cpp:12:22: warning: value computed is not used [-Wunused-value] 
foo.cpp:12:22: warning: statement has no effect [-Wunused-value] 

[W:\dev\test] 
> _