指向成员变量的指针

时间:2012-08-19 18:56:19

标签: c++

以下程序输出始终为1 1 1.在“C ++对象模型内部”一书中,提到它将给出偏移量。目的还在于找出对象布局。但是,我对输出感到困惑。使用g ++ 4.5.2

class Test
{
    public:
        float a;
        float b;
        float c;
};

int main()
{
    float Test::*ptr = &Test::a;
    float Test::*ptr1 = &Test::b;
    float Test::*ptr2 = &Test::c;
    cout<<ptr<<endl;
    cout<<ptr1<<endl;
    cout<<ptr2<<endl;

    return 0;
}

输出:

1
1
1

编辑(跟进问题): 在书中提到origin.y = 0可以转换为&origin + (Point3d::y-1),其中origin是Point3d的对象,y是Point3d类的成员变量。虽然当我编译它时给了我编译错误。

2 个答案:

答案 0 :(得分:17)

您无法打印指向成员的指针,但指向成员的指针可以隐式转换为bool,当然也可以打印。空指针转换为false,所有其他指针转换为true。默认情况下,std::coutfalse打印为0,将true打印为1

答案 1 :(得分:4)

您写道,您想要找到内存偏移量。虽然FredOverflow写的内容完全正确,但如果您想知道Testab的地址,则应该创建类c的实例。例如:

Test t;
float *ptr = &t.a;
float *ptr1 = &t.b;
float *ptr2 = &t.c;

在我的机器上,这会产生以下三个地址:

0x7fff564f8918
0x7fff564f891c
0x7fff564f8920

你会发现它们相距4个字节(或sizeof(float))并且Test的大小为12个字节(使用sizeof(Test))。此外,&t的地址0x7fff564f8918&t.a的地址相同。这就是如何形成类Test的实例的内存布局。

您还可以使用POD找到offsetof()类型成员的偏移量。

cout << offsetof(Test, a) << endl;
cout << offsetof(Test, b) << endl;
cout << offsetof(Test, c) << endl;

产量

0
4
8

请注意,offsetof(Test, b)

基本相同
(unsigned long long) &(((Test*) 0)->b) - (unsigned long long) (Test*) 0

回答您的后续问题:

由于与前面提到的相同的错误,该代码将无法工作。但是,如果您想计算y origin成员的地址并为其指定值0,则可以这样做:

class Point3d {
public:
  float x, y, z;
};

Point3d origin;
origin.y = 10;

// We take the address of origin, which points to the first member, 
// then add the offset to the member y.
float *ptr = (float*) ((unsigned long long) &origin + offsetof(Point3d, y));
cout <<  "Old value: " << *ptr << endl;
*ptr = 0;
cout <<  "New value: " << *ptr << endl;

产生输出:

Old value: 10
New value: 0

请再次记住,这只是因为Point3dPOD类型。