关于data member pointer的一些讨论

王朝other·作者佚名  2006-01-22
窄屏简体版  字體: |||超大  

今天为了测试data member pointer,在BCB6里写了一段程序,却发现了一点问题。

代码很简单:

struct Base1 { int val1;};

printf("&Base1::val1 = %p, %d\n", &Base1::val1, 2);

结果发现数字2 输出失败,显示为0,察看CPU发现:

0040116B 6A02 push 0x02

0040116D FF35A8204000 push dword ptr [0x4020A8]

00401173 FF35A4204000 push dword ptr [0x4020A4]

00401179 68D4204000 push 0x004020d4

0040117E E831020000 call CC3260MT._printf

00401183 83C410 add esp,0x10

原来第一个参数“两次”被push入栈,导致printf认为第一次push的就是%d的参数。将上面的程序改为:

printf("&Base1::val1 = %p, %d %d\n", &Base1::val1, 2);

后可以发现2的输出。

为什么会将pointer入栈两次?

----------------------------------------------------

1/9/2006通过一个简单的测试:

int Base1::*pp;

printf("%d\n",sizeof(pp));

发现在BCB中是8字节(即使将Data Alignment设置成word或者double word也没有区别),而在VC或者GNU C++中是4字节。

谢谢某鸟的解释,于是查了一下__closure。让人惊讶的是他可以让一个“普通”的函数指针指向“thiscall”调用的成员函数(Using a closure, you can get a pointer to member function for an object (i.e. a particular instance of a class). The object can be any object, regardless of its inheritance hierarchy. The object抯 this pointer is automatically used when calling the member function through the closure. )。看来多出来的4字节是用来记录this指针了。(结果也很好证实)

不过:

[问题一]:

为什么data member pointer也会多这4字节?用来做什么?还是只是单纯的为了统一?

试了几个case,包括虚拟继承,发现“后面”的4字节都是0。本来以为是记录继承类中基类的偏移量,发现不是。又以为和上面一样与this指针有关系,不过,data member pointer用this指针做什么?后来猜想为了决议二义性,但因为下面的问题,测试未遂。

[问题二]:

本来想做另外一个实验:

struct Base1 { int val1; };

struct Base2: Base1 { int val2;};

struct Base3: Base1 { int val3;};

struct Derived : Base2, Base3 {int val4;};

如果定义一个Derived d; 显然可以通过d.Base2::val1和d.Base3::val1来分别访问两个val1,但如果是data member pointer呢?如何解决二义性,用一个int Base1::*pp;如何分别访问两个val1?

我试了

pp = &Derived::Base2::val1;

pp = &Derived::Base2.val1;

pp = &Derived.Base2::val1;

pp = &Derived.Base2.val1;

都不行。

----------------------------------------------------

1/13/2005

本来只想把问题局限到BCB中,不过既然不停的提到了VC中data member pointer。我也说说自己的看法。

一如ICOM(《Incide The C++ Object Model》,《深入探索C++对象模型》)中说,一般data member pointer用offset+1,这样可以避免以下的混乱。

int Base1::*p1 = 0;

int Base1::*p2 = &Base1::val1;

但是在VC中直接用的是offset。VC中避免这种的混乱的方法是int Base1::*p1 = 0;这样语句,实际上把p1置成了0xFFFFFFFFH,而非像普通pointer一样的0。判断

if (p1 == 0)

被转换成为 cmp dword ptr[...], 0FFFFFFFFh

相当于说,BCB/GNU data member pointer的值 = VC data member pointer的值 + 1

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
 
 
© 2005- 王朝網路 版權所有 導航