剑灵分析的有一定的道理,我也认为是编译做了一些处理。为什么这样,我觉得一种情况是:
当ptrToMember=0时,是有其明确意义的,此时它指向的是第一个成员value,这样就可以确保程序员能够明确地将ptrToMember指向正确的成员。
int Base::*ptrToMember = NULL;
我将代码改成:
int Base::*ptrToMember = 0;
结果没有大的区别,编译还是会将-1赋值给了ptrToMember。
为了继续印证“指向成员变量的指针保存的是偏移量”这个说法,我对源代码做了些修改,以便于调试。
#include
using namespace std;
class Base
{
public:
Base(): value(10), value2(100) {}
void memberFunc() { cout << "just a testn"; }
public:
int value;
int value2;
};
int main()
{
Base b;
int i;
int Base::*ptrToMember = NULL;
printf("the ptrToMember is 0x%pn", ptrToMember);
i = b.*ptrToMember;
cout << "i=" << i << endl;
ptrToMember = &Base::value;
printf("the ptrToMember is 0x%pn", ptrToMember);
i = b.*ptrToMember;
cout << "i=" << i << endl;
ptrToMember = &Base::value2;
printf("the ptrToMember is 0x%pn", ptrToMember);
void (Base::*ptrToFunction)() = NULL;
printf("the ptrToFunction is 0x%pn", ptrToFunction);
ptrToFunction = &Base::memberFunc;
printf("the ptrToFunction is 0x%pn", ptrToFunction);
}
输出的结果如下:
the ptrToMember is 0xFFFFFFFF
i=2764
the ptrToMember is 0x00000000
i=10
the ptrToMember is 0x00000004
the ptrToFunction is 0x00000000
the ptrToFunction is 0x011F1032
在看看汇编代码:
; 20 : int Base::*ptrToMember = NULL;
mov DWORD PTR _ptrToMember$[ebp], -1
; 22 : i = b.*ptrToMember;
mov eax, DWORD PTR _ptrToMember$[ebp]
mov ecx, DWORD PTR _b$[ebp+eax]
mov DWORD PTR _i$[ebp], ecx
第一次i的值为2764对应的16进制的值为0xacc,为何是2764而不是其他的值?继续跟进,查看内存分布的情况:
对象b的地址为:0x003cfaf8。
则:
mov ecx, DWORD PTR _b$[ebp+eax] ;eax=-1
那么ecx的值为0x00000acc(注意这里是小端模式),同时也印证指向类成员指针确实是相对于某一个对象地址的偏移量。