15

我正在尝试使用 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);

甚至不编译?

4

2 回答 2

19

成员函数或指向它们的指针不存储在对象中。(virtual函数通常通过存储在表中的指针来调用,对象有一个指向该表的指针)这将浪费大量内存它们通常存储在代码内存部分中,并且为编译器所知。对象 ( *this) 通常作为不可见参数传递,因此函数在调用时知道要对哪个对象进行操作。

所以,用外行的话来说,你会有

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

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

a您正在调用的对象在哪里foo

于 2013-03-22T14:14:01.883 回答
4

成员函数指针实际上并不存储在对象中:没有必要。C++ 标准并没有具体说明如何实现例如虚函数,但是虚成员函数的常见做法是每个对象都包含一个指向函数指针表的指针。该指针称为vtable 指针

您可能会尝试了解 Stanley Lippman 的“Inside the C++ object model”

或者,在我当时的主页站点消失之前,您可能只是尝试获取我的旧指针教程,该教程曾经从 Wikipedia 的指针文章中引用。


关于第二个问题,为什么取地址p->memberFunc会让编译器有点窒息,那个表达式没有类型,它只是一个语法实体,你可以应用一个参数列表来调用函数。

以机智,

struct S
{
    void foo() {}
};

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

汇编:

[W:\开发\测试]
> g++ foo.cpp
foo.cpp:在函数'int main()'中:
foo.cpp:12:17: 错误:ISO C++ 禁止使用绑定成员函数的地址来形成指向成员函数的指针。说 '&S::foo' [-fpermissive]
foo.cpp:12:22:警告:未使用计算的值 [-Wunused-value]
foo.cpp:12:22:警告:语句无效 [-Wunused-value]

[W:\开发\测试]
> _
于 2013-03-22T14:12:58.787 回答