成员变量指针

5
以下程序的输出始终为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 类的成员变量。但是当我编译时会出现编译错误。

10
cout没有为成员指针重载插入运算符,所以ptr会被隐式转换为bool - Mr.Anubis
1
@Mr.Anubis:你应该把那个发表为答案。 - Ed S.
2个回答

20

您不能打印成员指针,但是可以将指向成员的指针隐式转换为bool,然后当然可以打印这些指针。空指针被转换为false,而所有其他指针都被转换为true。默认情况下,std::coutfalse打印为0,将true打印为1


6

您写道您想要查找内存偏移量。虽然FredOverflow所写的完全正确,但如果您想知道abc的地址,您应该创建一个Test类的实例。例如:

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

在我的电脑上,这将产生以下三个地址:
0x7fff564f8918
0x7fff564f891c
0x7fff564f8920

你会发现它们相隔4个字节(或sizeof(float)),并且使用sizeof(Test)时,Test的大小为12个字节。此外,&t的地址为0x7fff564f8918,与&t.a的地址相同。这就是类Test实例的内存布局形成的方式。
你也可以使用offsetof()查找POD类型成员的偏移量。
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

回答你的后续问题:

那段代码将无法工作,因为存在先前提到的同样错误。然而,如果你想要计算出originy成员的地址并将其赋值为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

再次记住,这仅仅是因为Point3d是一个POD类型才可能实现的。

在《C++对象模型内幕》一书中,明确提到它会给出偏移值。但是,即使我尝试比较这些指针或执行任何二进制操作,它仍然会抛出错误。我很困惑,不知道是由于gcc还是我的错误解释导致的!!! - K.K
我添加了一个回答来回应您的后续问题。 - Morten Kristensen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接