2013-03-22 93 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] 
> _