多继承+虚继承时内存布局,sizeof()怎么计算?
今天看到<<C++编程思想>>多重继承一章,P366
按照作者的分析所述,我勉强推出了sizeof(Bottom)=36是怎么来的。
代码见下:(有省略)
然而我在运行它的时候,无论是vc6还是dev c++显示的大小只有28B
这下我就完全弄不懂了,特此向各位牛人请教!
另:按照《虚继承之单继承的内存布局 》一文的分析,就应该是36啊,这倒底是
怎么回事呢?(该文出处: http://rkfang.cnblogs.com/archive/2004/10/10/50599.aspx )
=================
#include<iostream>
#include<cstdlib>
using namespace std;
class Top
{
protected:
int x;
public:
Top(int n):x(n){cout<<"Top"<<endl;}
virtual ~Top(){}
};
class Left:virtual public Top
{
protected:
int y;
public:
Left(int m,int n):Top(m){y=n;cout<<"Left"<<endl;}
};
class Right:public virtual Top
{
protected:
int z;
public:
Right(int m,int n):Top(m){z=n;cout<<"Right"<<endl;}
};
class Bottom:public Left,public Right
{
int w;
public:
Bottom(int i,int j,int k,int m):Top(i),Left(i,j),Right(i,k),w(m)
{
cout<<"Bottom"<<endl;
}
};
int main()
{
Bottom b(1,2,3,4);
cout<<"sizeof(b) "<<sizeof(b)<<","<<sizeof(Bottom)<<endl;
cout<<sizeof(Left)<<","<<sizeof(Right)<<","<<sizeof(Top)<<endl;
for(int i=0;i<sizeof(b);i+=4)
cout<<*(reinterpret_cast<int*>((&b)+i))<<"________"<<endl;
system("PAUSE");
}
=================
问题点数:100、回复次数:20Top
1 楼langzi8818(┤天道酬勤┝爱老婆┦┷我是来学习滴┷)回复于 2006-09-24 11:36:14 得分 5
接分,每个编译器实现不同Top
2 楼wanfustudio(雁南飞:知识之败,慕虚名而不务潜修也)回复于 2006-09-24 12:16:35 得分 5
不晓得 !
顶上去!Top
3 楼chenhu_doc(^0^纯一狼^0^ 看书看到大笑,直到不能自已)回复于 2006-09-24 12:31:45 得分 10
看inside the cpp object model
主要是
对象的vptr指针占用
和字节对齐的需要
两种情况占用内存。Top
4 楼chenhu_doc(^0^纯一狼^0^ 看书看到大笑,直到不能自已)回复于 2006-09-24 12:43:19 得分 0
当然,vptr占用考虑要单纯些,
字节对齐看个例子就可以了。
参考inside the cpp object model
的 3.4 Inheritance and the Data Member
Top
5 楼OOPhaisky(异化$渴望成功~~)回复于 2006-09-24 12:50:47 得分 50
按照一般情况,36应该是正确的,计算方法如下:
virtual class Top子对象(1个):4+4=8bytes(int x:4bytes, vptr:4bytes)
class Left子对象(1个):4+4+4=12bytes(int y:4bytes, vptr:4bytes,pointer to virtual base class:4bytes)
class Right子对象(1个):4+4+4=12bytes(int z:4bytes, vptr:4bytes,pointer to virtual base class:4bytes)
class Bottom子对象(1个):4bytes(int w:4bytes)
所以一共8+12+12+4=36bytes。
但是,各家编译器厂商的实现方法各有不同,比如,如果将class Left子对象和class Right子对象中的pointer to virtual base class与vptr合并到一起,那么class Left子对象和class Right子对象的大小就都是8bytes了,这样一来总共的大小就变成28bytes了。Top
6 楼songxin328(masm)回复于 2006-09-24 13:28:43 得分 0
谢谢各位的解答
在dev c++中各个类大小分别是
Bottom 28
Left 16(也许这个时候相当于Left是Top的最终实现,所以Top的数据成员还是有的)
Right 16
Top 8
我是这样计算的:
Bottom: vptr_Bottom + (int w) + vptr_Left + vbtbl_Left + vptr_Right
+ vbtbl_Right + (int y) + (int z) + (int x) + vptr_Top = 40(忘了最开始怎么推出的36了:()
OOPhaisky(异化$渴望成功~~) 在计算Bottom时为什么不考虑Bottom的虚函数指针呢?如果vptr_Bottom没有的话那么我的答案也是36了:)
另外,上面的字节数(28,16,16,8)无论是VC6 or Dev c++都是一样的
这里的数据int和指针都是4B,我想暂时没有因对齐而加入的字节吧?
1. 麻烦大家看看我的推导哪儿错了(都=40了)?
2. 28,36,怎么算出来的?
再次orz 谢!Top
7 楼steedhorse(晨星)回复于 2006-09-24 13:43:37 得分 20
忘了最开始怎么推出的36了:(
=============================
vptr_Bottom和vptr_Left(或vptr_Right,总归两者之一)可以共享。Top
8 楼steedhorse(晨星)回复于 2006-09-24 13:49:18 得分 0
还有的编译器实现中会把指向虚基类子对象的那个指针同样给塞到虚函数表的某一项中去,所以可能连36都不用了。
知道各种编译器各不相同就可以了。:)
究竟怎么个“不同”法,唉,什么实现都可能有。:(别去多管了。Top
9 楼songxin328(masm)回复于 2006-09-24 14:24:03 得分 0
感谢晨星的解答^_^
同样谢谢楼上的各位
今天晚点时候结贴:)Top
10 楼sinall()回复于 2006-09-24 15:31:03 得分 5
Top: 4(vptr) + 4(x) = 8
Left: 4(vptr) + 4(vptr to Top) + 4(x) + 4(y) = 16
Right: 4(vptr) + 4(vptr to Top) + 4(x) + 4(z) = 16
Bottom: 4(vptr) + 4(vptr to Left) + 4(vptr to Right) + 4(x) + 4(y) + 4(z) + 4(w) = 28
个人猜想,欢迎指正。Top
11 楼songxin328(masm)回复于 2006-09-24 15:44:34 得分 0
to sinall:
你所说的vptr to Top 是不是就是指向虚基表的指针?vbtbl_ptr_Top??
另外,因为Bottom的size只有28,除去四个数据成员16B后,只能存放3个指针
这三个放的是啥东东呢?
如sinall所言的:4(vptr) + 4(vptr to Left) + 4(vptr to Right)
还是:vptr_bottom,Left及Right中的vptr (或 vbtbl_ptr)?Top
12 楼corrupt(喜欢 睡在床板下 的思考)回复于 2006-09-24 15:49:10 得分 5
inside object model...
说的自己也不懂了Top
13 楼OOPhaisky(异化$渴望成功~~)回复于 2006-09-24 18:02:58 得分 0
OOPhaisky(异化$渴望成功~~) 在计算Bottom时为什么不考虑Bottom的虚函数指针呢?如果vptr_Bottom没有的话那么我的答案也是36了:)
---------------------------------------------------------------------------------
楼主可以为Bottom加上一个vptr指针,符合标准,行为也正确,但是我要说这是完全没有必要的!因为Bottom可以和Left或者Right共享vptr指针,因为Bottom对象一定是一个Left或者Right对象,其中一定有Left或者Right的成分,所以只要Left或者Right有vptr,那么Bottom就一定有vptr了。因此,相信大部分编译器都不会为Bottom单独设置一个vptr。
楼主如果对这一点有疑问,可以看看《more effective c++》120页,就是说的这个问题(inside the cpp model中应该也有介绍,但是太杂了,没找到)。Top
14 楼OOPhaisky(异化$渴望成功~~)回复于 2006-09-24 18:41:28 得分 0
我将<<more effective c++>>中的话给楼主贴一下吧:
-----------------------------------------------------------------------------------
class A {...};
class B :virtual public A {...};
class C :virtual public A {...};
class D :public B, public C {...};
......
...虽然涉及四个classes,却只出现三个vptrs。如果编译器喜欢,当然可以产生四个vptrs,但是三个已经足够了(B和D可以共享同一个vptr)。大部分编译器会采用这项好处,降低编译器所带来的额外开销。
-----------------------------------------------------------------------------------Top
15 楼songxin328(masm)回复于 2006-09-24 21:45:59 得分 0
太感谢 OOPhaisky(异化$渴望成功~~) 了!
我把整个大家的回帖又看了一遍,现在差不多理解了,虽然不
算太清楚:)
现在结贴。
3x 2 all!Top
16 楼guqst(过关斩将)回复于 2006-09-26 09:13:17 得分 0
bottom:
2个vbtable
1个vftable
4个成员Top
17 楼michaelysj(其实我很傻...)回复于 2006-10-28 21:22:40 得分 0
markTop
18 楼jiang_nan1981()回复于 2006-10-29 20:02:08 得分 0
markTop
19 楼zjbirdman()回复于 2006-11-12 20:01:02 得分 0
markTop
20 楼dukang_2005(杜康)回复于 2007-04-16 10:11:19 得分 0
你要是在Left,和Right中都加一个虚函数(析构除外)的话就36了Top




