首页 > 代码库 > C++ 继承之虚继承与普通继承的内存分布
C++ 继承之虚继承与普通继承的内存分布
仅供互相学习,请勿喷,有观点欢迎指出~
class A{ virtual void aa(){};};class B : public virtual A{ char j[3]; //加入一个变量是为了看清楚class中的vfptr放在什么位置public: virtual void bb(){};};class C : public virtual A{ char i[3];public: virtual void cc(){};};class C1 : public A{ char i1[3];public: virtual void cc1(){};};class D : public C{ char d[3];public: virtual void dd(){};};class D1 : public C1{ char d1[3];public: virtual void dd1(){};};class E : public virtual C{ char e[3];public: virtual void ee(){};};class E1 : public virtual C1{ char e1[3];public: virtual void ee1(){};};class F : public C, public virtual B{ char f[3];public: virtual void ff(){};};class F1 : public virtual C, public B{ char f1[3];public: virtual void ff1(){};};class G : public virtual E{ char g[3];public: virtual void gg(){};};class H : public virtual E, public virtual C{ char h[3];public: virtual void hh(){};};class H1 : public E, public C1{ char h1[3];public: virtual void hh1(){};};
在VS2013下,在项目->属性->C/C++->命令行中添加/d1reportAllClassLayout即可查看所有类的内存分布情况:
1> class A size(4):1> +---1> 0 | {vfptr}1> +---1> 1> A::$vftable@:1> | &A_meta1> | 01> 0 | &A::aa 1> 1> A::aa this adjustor: 01> 1> 1> class B size(16):1> +---1> 0 | {vfptr}1> 4 | {vbptr}1> 8 | j1> | <alignment member> (size=1)1> +---1> +--- (virtual base A)1> 12 | {vfptr}1> +---1> 1> B::$vftable@B@:1> | &B_meta1> | 01> 0 | &B::bb 1> 1> B::$vbtable@:1> 0 | -41> 1 | 8 (Bd(B+4)A)1> 1> B::$vftable@A@:1> | -121> 0 | &A::aa 1> 1> B::bb this adjustor: 01> 1> vbi: class offset o.vbptr o.vbte fVtorDisp1> A 12 4 4 01> 1> 1> class C size(16):1> +---1> 0 | {vfptr}1> 4 | {vbptr}1> 8 | i1> | <alignment member> (size=1)1> +---1> +--- (virtual base A)1> 12 | {vfptr}1> +---1> 1> C::$vftable@C@:1> | &C_meta1> | 01> 0 | &C::cc 1> 1> C::$vbtable@:1> 0 | -41> 1 | 8 (Cd(C+4)A)1> 1> C::$vftable@A@:1> | -121> 0 | &A::aa 1> 1> C::cc this adjustor: 01> 1> vbi: class offset o.vbptr o.vbte fVtorDisp1> A 12 4 4 01> 1> 1> class C1 size(8):1> +---1> | +--- (base class A)1> 0 | | {vfptr}1> | +---1> 4 | i11> | <alignment member> (size=1)1> +---1> 1> C1::$vftable@:1> | &C1_meta1> | 01> 0 | &A::aa 1> 1 | &C1::cc1 1> 1> C1::cc1 this adjustor: 01> 1> 1> class D size(20):1> +---1> | +--- (base class C)1> 0 | | {vfptr}1> 4 | | {vbptr}1> 8 | | i1> | | <alignment member> (size=1)1> | +---1> 12 | d1> | <alignment member> (size=1)1> +---1> +--- (virtual base A)1> 16 | {vfptr}1> +---1> 1> D::$vftable@C@:1> | &D_meta1> | 01> 0 | &C::cc 1> 1 | &D::dd 1> 1> D::$vbtable@:1> 0 | -41> 1 | 12 (Dd(C+4)A)1> 1> D::$vftable@A@:1> | -161> 0 | &A::aa 1> 1> D::dd this adjustor: 01> 1> vbi: class offset o.vbptr o.vbte fVtorDisp1> A 16 4 4 01> 1> 1> class D1 size(12):1> +---1> | +--- (base class C1)1> | | +--- (base class A)1> 0 | | | {vfptr}1> | | +---1> 4 | | i11> | | <alignment member> (size=1)1> | +---1> 8 | d11> | <alignment member> (size=1)1> +---1> 1> D1::$vftable@:1> | &D1_meta1> | 01> 0 | &A::aa 1> 1 | &C1::cc1 1> 2 | &D1::dd1 1> 1> D1::dd1 this adjustor: 01> 1> 1> class E size(28):1> +---1> 0 | {vfptr}1> 4 | {vbptr}1> 8 | e1> | <alignment member> (size=1)1> +---1> +--- (virtual base A)1> 12 | {vfptr}1> +---1> +--- (virtual base C)1> 16 | {vfptr}1> 20 | {vbptr}1> 24 | i1> | <alignment member> (size=1)1> +---1> 1> E::$vftable@:1> | &E_meta1> | 01> 0 | &E::ee 1> 1> E::$vbtable@E@:1> 0 | -41> 1 | 8 (Ed(E+4)A)1> 2 | 12 (Ed(E+4)C)1> 1> E::$vftable@A@:1> | -121> 0 | &A::aa 1> 1> E::$vftable@C@:1> | -161> 0 | &C::cc 1> 1> E::$vbtable@C@:1> 0 | -41> 1 | -8 (Ed(C+4)A)1> 1> E::ee this adjustor: 01> 1> vbi: class offset o.vbptr o.vbte fVtorDisp1> A 12 4 4 01> C 16 4 8 01> 1> 1> class E1 size(20):1> +---1> 0 | {vfptr}1> 4 | {vbptr}1> 8 | e11> | <alignment member> (size=1)1> +---1> +--- (virtual base C1)1> | +--- (base class A)1> 12 | | {vfptr}1> | +---1> 16 | i11> | <alignment member> (size=1)1> +---1> 1> E1::$vftable@E1@:1> | &E1_meta1> | 01> 0 | &E1::ee1 1> 1> E1::$vbtable@:1> 0 | -41> 1 | 8 (E1d(E1+4)C1)1> 1> E1::$vftable@C1@:1> | -121> 0 | &A::aa 1> 1 | &C1::cc1 1> 1> E1::ee1 this adjustor: 01> 1> vbi: class offset o.vbptr o.vbte fVtorDisp1> C1 12 4 4 01> 1> 1> class F size(32):1> +---1> | +--- (base class C)1> 0 | | {vfptr}1> 4 | | {vbptr}1> 8 | | i1> | | <alignment member> (size=1)1> | +---1> 12 | f1> | <alignment member> (size=1)1> +---1> +--- (virtual base A)1> 16 | {vfptr}1> +---1> +--- (virtual base B)1> 20 | {vfptr}1> 24 | {vbptr}1> 28 | j1> | <alignment member> (size=1)1> +---1> 1> F::$vftable@C@:1> | &F_meta1> | 01> 0 | &C::cc 1> 1 | &F::ff 1> 1> F::$vbtable@C@:1> 0 | -41> 1 | 12 (Fd(C+4)A)1> 2 | 16 (Fd(F+4)B)1> 1> F::$vftable@A@:1> | -161> 0 | &A::aa 1> 1> F::$vftable@B@:1> | -201> 0 | &B::bb 1> 1> F::$vbtable@B@:1> 0 | -41> 1 | -8 (Fd(B+4)A)1> 1> F::ff this adjustor: 01> 1> vbi: class offset o.vbptr o.vbte fVtorDisp1> A 16 4 4 01> B 20 4 8 01> 1> 1> class F1 size(32):1> +---1> | +--- (base class B)1> 0 | | {vfptr}1> 4 | | {vbptr}1> 8 | | j1> | | <alignment member> (size=1)1> | +---1> 12 | f11> | <alignment member> (size=1)1> +---1> +--- (virtual base A)1> 16 | {vfptr}1> +---1> +--- (virtual base C)1> 20 | {vfptr}1> 24 | {vbptr}1> 28 | i1> | <alignment member> (size=1)1> +---1> 1> F1::$vftable@B@:1> | &F1_meta1> | 01> 0 | &B::bb 1> 1 | &F1::ff1 1> 1> F1::$vbtable@B@:1> 0 | -41> 1 | 12 (F1d(B+4)A)1> 2 | 16 (F1d(F1+4)C)1> 1> F1::$vftable@A@:1> | -161> 0 | &A::aa 1> 1> F1::$vftable@C@:1> | -201> 0 | &C::cc 1> 1> F1::$vbtable@C@:1> 0 | -41> 1 | -8 (F1d(C+4)A)1> 1> F1::ff1 this adjustor: 01> 1> vbi: class offset o.vbptr o.vbte fVtorDisp1> A 16 4 4 01> C 20 4 8 01> 1> 1> class G size(40):1> +---1> 0 | {vfptr}1> 4 | {vbptr}1> 8 | g1> | <alignment member> (size=1)1> +---1> +--- (virtual base A)1> 12 | {vfptr}1> +---1> +--- (virtual base C)1> 16 | {vfptr}1> 20 | {vbptr}1> 24 | i1> | <alignment member> (size=1)1> +---1> +--- (virtual base E)1> 28 | {vfptr}1> 32 | {vbptr}1> 36 | e1> | <alignment member> (size=1)1> +---1> 1> G::$vftable@G@:1> | &G_meta1> | 01> 0 | &G::gg 1> 1> G::$vbtable@:1> 0 | -41> 1 | 8 (Gd(G+4)A)1> 2 | 12 (Gd(G+4)C)1> 3 | 24 (Gd(G+4)E)1> 1> G::$vftable@A@:1> | -121> 0 | &A::aa 1> 1> G::$vftable@C@:1> | -161> 0 | &C::cc 1> 1> G::$vbtable@C@:1> 0 | -41> 1 | -8 (Gd(C+4)A)1> 1> G::$vftable@E@:1> | -281> 0 | &E::ee 1> 1> G::$vbtable@E@:1> 0 | -41> 1 | -20 (Gd(E+4)A)1> 2 | -16 (Gd(E+4)C)1> 1> G::gg this adjustor: 01> 1> vbi: class offset o.vbptr o.vbte fVtorDisp1> A 12 4 4 01> C 16 4 8 01> E 28 4 12 01> 1> 1> class H size(40):1> +---1> 0 | {vfptr}1> 4 | {vbptr}1> 8 | h1> | <alignment member> (size=1)1> +---1> +--- (virtual base A)1> 12 | {vfptr}1> +---1> +--- (virtual base C)1> 16 | {vfptr}1> 20 | {vbptr}1> 24 | i1> | <alignment member> (size=1)1> +---1> +--- (virtual base E)1> 28 | {vfptr}1> 32 | {vbptr}1> 36 | e1> | <alignment member> (size=1)1> +---1> 1> H::$vftable@H@:1> | &H_meta1> | 01> 0 | &H::hh 1> 1> H::$vbtable@:1> 0 | -41> 1 | 8 (Hd(H+4)A)1> 2 | 12 (Hd(H+4)C)1> 3 | 24 (Hd(H+4)E)1> 1> H::$vftable@A@:1> | -121> 0 | &A::aa 1> 1> H::$vftable@C@:1> | -161> 0 | &C::cc 1> 1> H::$vbtable@C@:1> 0 | -41> 1 | -8 (Hd(C+4)A)1> 1> H::$vftable@E@:1> | -281> 0 | &E::ee 1> 1> H::$vbtable@E@:1> 0 | -41> 1 | -20 (Hd(E+4)A)1> 2 | -16 (Hd(E+4)C)1> 1> H::hh this adjustor: 01> 1> vbi: class offset o.vbptr o.vbte fVtorDisp1> A 12 4 4 01> C 16 4 8 01> E 28 4 12 01> 1> 1> class H1 size(40):1> +---1> | +--- (base class E)1> 0 | | {vfptr}1> 4 | | {vbptr}1> 8 | | e1> | | <alignment member> (size=1)1> | +---1> | +--- (base class C1)1> | | +--- (base class A)1> 12 | | | {vfptr}1> | | +---1> 16 | | i11> | | <alignment member> (size=1)1> | +---1> 20 | h11> | <alignment member> (size=1)1> +---1> +--- (virtual base A)1> 24 | {vfptr}1> +---1> +--- (virtual base C)1> 28 | {vfptr}1> 32 | {vbptr}1> 36 | i1> | <alignment member> (size=1)1> +---1> 1> H1::$vftable@E@:1> | &H1_meta1> | 01> 0 | &E::ee 1> 1 | &H1::hh1 1> 1> H1::$vftable@C1@:1> | -121> 0 | &A::aa 1> 1 | &C1::cc1 1> 1> H1::$vbtable@E@:1> 0 | -41> 1 | 20 (H1d(E+4)A)1> 2 | 24 (H1d(E+4)C)1> 1> H1::$vftable@A@:1> | -241> 0 | &A::aa 1> 1> H1::$vftable@C@:1> | -281> 0 | &C::cc 1> 1> H1::$vbtable@C@:1> 0 | -41> 1 | -8 (H1d(C+4)A)1> 1> H1::hh1 this adjustor: 01> 1> vbi: class offset o.vbptr o.vbte fVtorDisp1> A 24 4 4 01> C 28 4 8 0
总结出单继承内存分布大致如下:
- 普通继承情况下,先父类元素后子类元素,若父类元素本身也是从某个爷爷类继承而来:父类是虚继承而来,则先父后子再爷爷(其实这个分布是满足规则2的),即爷爷放在最后;父类是普通继承而来,先爷爷后父再子,即爷爷放在前面。
- 虚继承情况下,先子类元素后父类元素,如果父类元素本身也是从某个爷爷类继承(不论是虚继承还是普通继承)而来,则父类由类的深到浅依次分布(先爷爷后父,爷爷在子和父之间)。
多继承的内存分布情况如下:
- 虚继承和普通继承同时存在的情况下,先进行普通继承,再进行虚继承。
- 继承都是虚继承或者普通继承的时候,按照从左到右声明顺序进行继承,注意,都是虚继承的话,如果继承的相同的类,这个类只会在最先出现的地方出现一次而已;如果是普通继承,相同的类会多次出现。
总之,先满足基本的父子类分布情况,如果父类还有更深层次的基类,这些基类再依据普通继承和虚继承的情况进行内存分布(即红字标注部分)。另外,具体内存分布情况会不会还与编译环境有关就不得而知了,至少sizeof类的大小是会与编译环境有关的(http://www.cnblogs.com/yanqi0124/p/3829964.html文章最后对比了gcc和VC下sizeof的不同,因为对虚表指针的处理方式不同)
根据上述解释,就能解释程序员面试宝典中的一题:
class A{ virtual aa(){};};class B : public virtual A{ char j[3]; //加入一个变量是为了看清楚class中的vfptr放在什么位置 public: virtual bb(){};};class C : public virtual B{ char i[3]; public: virtual cc(){};};
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。