C ++中指向数据成员的指针的值

时间:2013-08-29 11:57:18

标签: c++ pointers offset pointer-to-member object-layout

遇到一个非常奇怪的问题,有谁知道这是什么原因?代码在Visual Studio 2012下进行测试。

#include <iostream>
struct A {
  int a;
};
struct B {
  int b;
};
struct C : public A, public B {
  int c;
};

int main() {
  int C::*p = &C::b;
  std::printf("%p\n", &C::b); //00000000
  std::printf("%p\n", p);     //00000004
  return 0;
}

2 个答案:

答案 0 :(得分:2)

指向成员的指针不仅仅是普通的C指针,因此将它们传递给printf实际上是未定义的行为,因为printf会相信"%p"并且C-cast指针 - 成为void*的成员。

标准允许的成员指针的唯一转换列在第4.11段:

  1. 空指针常量可以转换为空成员指针值
  2. 如果B是D的可访问,nonambiguos和非虚拟基类,则
  3. B::*T可以转换为D::*T
  4. 指向成员的指针实际上可能有不同的大小,具体取决于他们指向的类。

    有关MSVC中指针到成员实现的更多信息,请参阅此处:http://blogs.msdn.com/b/oldnewthing/archive/2004/02/09/70002.aspx

答案 1 :(得分:0)

注意可能出乎意料的结果:

printf("typeid(&C::b) = %s\n",typeid(&C::b).name());
printf("typeid(&B::b) = %s\n",typeid(&B::b).name());

VS2010上的产量:

typeid(&C::b) = int B::*
typeid(&B::b) = int B::*

这表明&amp; C :: b的结果类型是类型B上的成员指针。由于C是从B派生的,指针可以自由转换为类型C上的成员指针。这解释了两者之间的区别你看到的价值观。 &amp; C :: b是类型B上的成员函数指针,int C :: * p是类型C上的成员函数指针。

int B::*p_b = &B::b;
int C::*p_c = p_b;
printf("p_b = %p\n", p_b);
printf("p_c = %p\n", p_c);