虚拟继承问题__跪求解释

OOPhaisky 2006-04-01 11:25:50
class X
{public:int a;};

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

class Z : virtual public X
{};

class A : public Y, public Z
{};

int main(int argc, char *argv[])
{
X x;
Y y;
int a = 0, b = 0, c = 0;
y.b = 3;
y.a = 4;
memcpy(&a, &y, 4);
memcpy(&b, &y + 4, 4);
memcpy(&c, &y + 8, 4);
system("pause"); //在此处加上断点
}

然后debugging,在监视(watch)窗口中察看下列值:
&y 0x0012ff4c
&((y).b) 0x0012ff50
&(*(X*)(&y)) 0x0012ff54
由这些值我可以判断对象y的布局为:
0x0012ff4c ——————————
| 指向X部分的指针 |————
0x0012ff50 —————————— |
| y中的b | |
0x0012ff54 —————————— |
| (虚拟基类)X中的a |<————
——————————

然后我想看看“指向X部分的指针”值是否为“(虚拟基类)X中的a”的地址值-----这就是我在main函数中写了三个memcpy的原因。但是我在监视窗口中添加了三项“a,b,c”,它们的显示结果并不如我所意料:
a 0x00415710(预计应该为:0x0012ff54,即上图中“(虚拟基类)X中的a”的地址)
b 0xfe263ae0(预计应该为:0x00000003,即y.a)
c 0x0041107d(预计应该为:0x00000004,即y.b)

这到底是为什么呢?请高手给指点一二,小弟不胜感激,在此先谢谢了!!
...全文
502 18 打赏 收藏 转发到动态 举报
写回复
用AI写文章
18 条回复
切换为时间正序
请发表友善的回复…
发表回复
firetoucher 2006-04-03
  • 打赏
  • 举报
回复
2 OOPhaisky(渴望成功)
很不好意思,最近忙。
首先说,我这里还没有VS2005,所以不能帮你写出你 想要效果 的程序。
你说的不错。记录是否对象为最终子类的标记(太长,以下简称标记)是“类”的东西,而不是“对象”。很容易想到比较符合情理的做法是用处理虚函数的办法,象vptr和vtbl一样。在类里记录标记,而在对象中包含一个记录这个信息的指针。但是这在没有虚函数和运行时类型信息时,是否有点“铺张浪费”?当然类里记录的还应该有vbass的指针等等.....这些,甚至有些都还是悬而未决。所以我不知道用什么词语,一个带引号的“函数表”,是借用vtbl的表达。
而编译器如果觉得这样一点东西都需要二次访问,可能会不用指针,而直接写在对象里。所以我才那样说。
由于本身C++的virtual继承就问题不断,其实现更是千奇百怪。
今天喝醉了,有胡言乱语之处,请原谅。

FT
--
Anything one man can imagine, other men can make real.
Cicinho 2006-04-02
  • 打赏
  • 举报
回复
最后补充说一下的就是C++的多重继承技术并不强壮,而且会出现很多问题,不推荐使用多重继承,有点像是在讨论用不着的东西。
OpenHero 2006-04-02
  • 打赏
  • 举报
回复
class A
{
public:
int a;
};

class B : virtual public A
{
public:
int b;
};

class C : virtual public A
{
public:
//int c; // 打开 3
};

class D : public C, public B
{
public:
//int d; // 打开 4
};



int _tmain(int argc, _TCHAR* argv[])
{
A x;
D y;
int a = 0, b = 0, c = 0;
y.b = 3;
y.a = 4;



int *y1 = (int*)(&y);
memcpy(&a, y1, 4);
memcpy(&b, y1 + 1, 4);
memcpy(&c, y1 + 2, 4);
cout << a << " " << b << " " << c <<" " << endl;
//system("pause"); //在此处加上断点
return 0;
}

3.
&(y.c) 0x0012febc
&y 0x0012feb8
&(*(C*)(&y)) 0x0012feb8
&(*(B*)(&y)) 0x0012fec0
&(y.b) 0x0012fec4
&(*(A*)(&(y.a)) 0x0012fec8

4.
&(y.d) 0x0012feb8
&y 0x0012feb4
&(*(C*)(&y)) 0x0012feb4
&(*(B*)(&y)) 0x0012febc
&(y.b) 0x0012fec0
&(y.c) 0x0012fec4
&(*(A*)(&(y.a)) 0x0012fec8
OpenHero 2006-04-02
  • 打赏
  • 举报
回复
class A
{
public:
int a;
};

class B : virtual public A
{
public:
int b;
};

class C : virtual public A
{};

class D : public C, public B
{};



int _tmain(int argc, _TCHAR* argv[])
{
A x;
B y; // ----->这里为B时候内存是 下面1的情况
//D y; // ----->这里为D的时候y的内存如下2;
int a = 0, b = 0, c = 0;
y.b = 3;
y.a = 4;



int *y1 = (int*)(&y);
memcpy(&a, y1, 4);
memcpy(&b, y1 + 1, 4);
memcpy(&c, y1 + 2, 4);
cout << a << " " << b << " " << c <<" " << endl;
//system("pause"); //在此处加上断点
return 0;
}

1.
&y 0x0012fec0
&(y.b) 0x0012fec4
&(*(A*)(&y)) 0x0012fec8
&(*(A*)(&(y.a)) 0x0012fec8

2.
&y 0x0012febc
&(*(C*)(&y)) 0x0012febc
&(*(B*)(&y)) 0x0012fec0
&(y.b) 0x0012fec4
&(*(A*)(&(y.a)) 0x0012fec8
OpenHero 2006-04-02
  • 打赏
  • 举报
回复
各个编译器都有各自的实现方式,多重继承又可能带来更大的开销,并不强壮
OpenHero 2006-04-02
  • 打赏
  • 举报
回复
在虚基类的继承中,为了实现指向一个基类, vc的做法是使用了指向virtual base class table 的指针
junguo 2006-04-01
  • 打赏
  • 举报
回复
你应该这样做!由于编译器会对你的&y + 4进行处理,得到的并不是你想到的在y的地址基础上再加4,而是加上了4个Y的长度.
junguo 2006-04-01
  • 打赏
  • 举报
回复
class X
{public:int a;int c;};

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

class Z : virtual public X
{};

class A : public Y, public Z
{};

int main(int argc, char *argv[])
{
X x;
Y y;
int a = 0, b = 0, c = 0;
y.b = 3;
y.a = 4;



int *y1 = (int*)(&y);
memcpy(&a, y1, 4);
memcpy(&b, y1 + 1, 4);
memcpy(&c, y1 + 2, 4);
cout << a << " " << b << " " << c <<" " << endl;
system("pause"); //在此处加上断点
}
suuny919 2006-04-01
  • 打赏
  • 举报
回复
MARK...
OpenHero 2006-04-01
  • 打赏
  • 举报
回复
从你给的例子里面看不出来,只是在编译编译器解析的过程种才有?
???
OpenHero 2006-04-01
  • 打赏
  • 举报
回复
知其然,而不知其所以然,mark
OOPhaisky 2006-04-01
  • 打赏
  • 举报
回复
补充:
上面的图有些错位,但是我想大家能看清楚大概形状。
OpenHero 2006-04-01
  • 打赏
  • 举报
回复
一般放在末尾?
howyougen 2006-04-01
  • 打赏
  • 举报
回复
mark
lei001 2006-04-01
  • 打赏
  • 举报
回复
mark
OOPhaisky 2006-04-01
  • 打赏
  • 举报
回复
to firetoucher(风焱):

还有,我所举的例子中并没有virtual function,所以不应该有“函数表”,那在对象起始处的4个字节一定包含着指向其他信息的指针(比如你说的“录是否对象为最终子类的标记”),能不能给一个例子说明一下,谢谢
OOPhaisky 2006-04-01
  • 打赏
  • 举报
回复
to junguo(junguo):

你说的对,我忽略指针算术运算时需要注意的问题了 。

to firetoucher(风焱):

我用的是microsoft visual studio.net 2005编译环境。的确如你所说,“1很可能得到的是不是你想要的指向X部分的指针,”,我同样知道“对于virtual继承,ctor对于是否为最终子类有不同的行为”。但是,“很可能是y的“函数表”或者记录是否对象为最终子类的标记等”,这句话的后半部分我不是很理解,即“记录是否对象为最终子类的标记”,对于一个具体的对象,它当中肯定有最终子类的subobject,那是不是“在每一个subobject当中都有一处记录此subobject是否为最终子类”,还是“在此对象中只有一处记录整个对象里面所有subobject是否为最终子类”?
firetoucher 2006-04-01
  • 打赏
  • 举报
回复
1 memcpy(&a, &y, 4);
2 我想看看“指向X部分的指针”值是否为“(虚拟基类)X中的a”的地址值
3 0x00415710(预计应该为:0x0012ff54,即上图中“(虚拟基类)X中的a”的地址)
--
首先,你想要得东西并不是C++的标准。而是编译器的行为,每一个编译器都可能有不同的布局。至少,你应该写出你的环境。

其次,除楼上说的以外。很可惜,1很可能得到的是不是你想要的“指向X部分的指针”,很可能是y的“函数表”或者记录是否对象为最终子类的标记等。因为对于virtual继承,ctor对于是否为最终子类有不同的行为。
我说很可能,因为不知道你的编译器是什么。但印象中大多数编译器并没有把“指向X部分的指针”放在那里。


FT
--
Anything one man can imagine, other men can make real.

65,210

社区成员

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

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