关于C ++中指向数据成员的指针的一些混淆

时间:2018-01-07 15:09:10

标签: c++

class Foo {
    public:
    int a = 1;
    int b = 2;
};

int main() {
    Foo foo;
    cout << &Foo::a << endl;//output 1
    cout << &Foo::b << endl;//also output 1
}

我们知道指向成员数据的指针应指出与对象起始地址的相对偏移量,但正如示例所示,指向Foo :: a和Foo :: b的指针都得到1。有人能解释这里发生了什么吗?

3 个答案:

答案 0 :(得分:6)

首先,指向成员的指针不需要实现为对象&#34;起始地址的偏移量。 (不属于语言标准的概念)。事实上,某些类型的成员指针无法像这样实现。

相反,您所看到的只是basic_ostream::operator<<(bool)。成员的指针不能隐式转换为许多其他类型,但它们可以转换为bool。您查看的1只是表明您已经传递了非空成员指针。

答案 1 :(得分:4)

虽然Sneftel提供的answer是正确的,但这是查看指向成员的指针的“实际”(内部)值的一种方法:

#include <iostream>

struct x {
    int a, b;
};

int main() {
    int x::* pa = &x::a;
    int x::* pb = &x::b;

    std::cout << pa << ' ' << pb << '\n';
    std::cout << *(int*)&pa << ' ' << *(int*)&pb << '\n';
}

Try it online!

这可能有不同的值或导致未定义的行为,取决于实现。此外,我们无法保证sizeof int == sizeof pa

答案 2 :(得分:4)

大多数编译器都支持使用offsetof中定义的<cstddef>宏。请注意陷阱,引用cppreference

  

如果type不是标准布局类型,则行为未定义   (直到C ++ 17)有条件地支持使用offsetof宏   (自C ++ 17起)。

     

如果member是静态成员或成员函数,则行为是   未定义。

示例:

#include <iostream>
#include <cstddef>

class Foo {
public:
    int a;
    int b;
};

int main() {
    std::cout << offsetof(Foo, a) << std::endl;
    std::cout << offsetof(Foo, b) << std::endl;
}