粗看了<>,做了一个试验,但还是有些不解。(大家一起讨论吧)

heidongstar 2004-08-11 05:40:26
代码如下,我主要想验证一下第三章作者说的data布局那块。
#include <iostream.h>

class X {void pp(){cout<<"dsdf"<<endl;};};

class Y : public virtual X
{
public:
int yy;

};

class Z : public virtual X
{
public:
int zz;

};

class A : public Y, public Z {};

void main()
{
int s,d;
Y y,yy;
A aa;
aa.yy=0x12345678;
aa.zz=0x87654321;
int* a=(int *)(&aa) ;

s=*(a+2);
d=*(a+6);
cout<<hex<<s<<endl<<d<<endl;
}

vc6 debug模式内存dump如下:
0012FF58 34 80 42 00 78 56 34 12
0012FF60 28 80 42 00 21 43 65 87
0012FF68 1C 80 42 00 CC CC CC CC
0012FF70 1C 80 42 00 CC CC CC CC
0012FF78 CC CC CC CC CC CC CC CC

0x0012ff58是aa的首地址,理论上来说,前八个字节似乎为Y子对象,后八个字节为Z子对象,且各自的
前四个字节应该相同,因为他们Y和Z有共同的虚基类X。事实上不同,不知为什么?
另外0x0012FF68处和0012FF78相同,我怀疑他们才是指向虚基类的指针,可布局又不对啊。

大家讨论讨论,争取把这个问题弄清,共同进步嘛。
...全文
178 13 打赏 收藏 转发到动态 举报
写回复
用AI写文章
13 条回复
切换为时间正序
请发表友善的回复…
发表回复
xuzheng318 2004-08-12
  • 打赏
  • 举报
回复
学习了
freefalcon 2004-08-12
  • 打赏
  • 举报
回复
昨天回答写了一半时本人拖走了,今天还是贴出来吧

--------------------
我也在看这本书,不过还没时间细看
像这种涉及C++中的高级特性的地方,各编译器的实现不尽相同,书中也多次强调了这一点

看如下的代码
class X {
public: int xx;
};

class Y : public virtual X
{
public: int yy;
};

class Z : public virtual X
{
public: int zz;
};

class A : public Y, public Z
{
public:int aa;
};

void main()
{
A a;
a.xx = 1; a.yy = 2; a.zz = 3; a.aa = 4;
}

其内存布局为:
0012FF68 28 E0 42 00 02 00 00 00 Y子对象
0012FF70 1C E0 42 00 03 00 00 00 Z子对象
0012FF78 04 00 00 00 01 00 00 00 前4个字节为A自身的数据成员,后面为公共的X子对象

可以看出前8个字节为Y子对象,接着为Z子对象,再接着为A自身成员,最后为公共的X子对象

那Y,Z各自前4个字节为什么内容呢?
楼主可以跟踪到0x0042E01C处,这里便是和虚基类相关的一个表,根据多次测试可以得出:
这个表每个表项占12个字节,前4个字节与虚函数有关,没有虚函数时为0,有时为-4;
中间4个字节是this指针的调整量
后面4个字节通常为0,在有多个虚基类时才可能被设置,但还不清楚其具体意思

各个编译器在此存在较大的差异,Dev-C++中我还没测试,主要是其调试功能太弱了,用着不方便
heidongstar 2004-08-11
  • 打赏
  • 举报
回复
终于明白虚基类的意思了,就是说保证它的子类有且只有一个父对象。
heidongstar 2004-08-11
  • 打赏
  • 举报
回复
dev c++下结果如下,看看,多符合标准啊。看来像研究c++标准还得拿gcc.

0x22ff30 22ff40
0x22ff34 12345678
0x22ff38 22ff40
0x22ff3c 87654321
0x22ff40 77c08a55
0x22ff44 0
0x22ff48 0
0x22ff4c 7ffdf000
diaoni 2004-08-11
  • 打赏
  • 举报
回复
呃,那本书很久之前看的,具体不记得了,但Lipman在书中好象提到过一种实现,就是用一个指针指向一小段汇编代码,用该汇编代码进行类型转换,那两个莫名其妙的值可能就跟之有关吧:)
terryfjh 2004-08-11
  • 打赏
  • 举报
回复
不错
diaoni 2004-08-11
  • 打赏
  • 举报
回复
很显然,A中,Y和Z的子对象的前4位放的并不是X子对象的地址(我在X中加了一个int型的member后,那两个地方的值还是不同),事实上,那是和实现有关的,不同的编译器可能会不同,楼主可以用dev-c++试一下
diaoni 2004-08-11
  • 打赏
  • 举报
回复
你的dump不好看,用我的可以很好看到A的结构
void main()
{
using namespace std;

A aa;
aa.yy=0x12345678;
aa.zz=0x87654321;

unsigned int *pt=(unsigned int*)(&aa);

cout.setf(ios::hex,ios::basefield);
for(int i=0;i<sizeof(aa)/sizeof(unsigned int);++i)
{
cout<<(void*)(pt+i)<<" "<<(*(pt+i))<<endl;
}
X *px=&aa;
cout<<(void*)(px)<<endl;
Y *py=&aa;
cout<<(void*)(py)<<endl;
Z *pz=&aa;
cout<<(void*)(pz)<<endl;
}
输出如下:
0012FF70 46f02c
0012FF74 12345678
0012FF78 46f020
0012FF7C 87654321
0012FF80
0012FF70
0012FF78
Press any key to continue

呵呵,一目了然了
readi 2004-08-11
  • 打赏
  • 举报
回复
关注,学习,帮忙顶
waini12 2004-08-11
  • 打赏
  • 举报
回复
1 我不明白为什么结果会有 5个呢 你输出的分明就只有s跟d两个字母
2 为什么结果你要用0x形式输出呢 s d分明就是两个int呀
hxblvc 2004-08-11
  • 打赏
  • 举报
回复
注关一下
heidongstar 2004-08-11
  • 打赏
  • 举报
回复
可叹军中无人那,sign.
heidongstar 2004-08-11
  • 打赏
  • 举报
回复
为什么就没人看呢,多好的帖子啊。

64,637

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧