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::[email protected]:
1>      | &A_meta
1>      |  0
1>   0    | &A::aa
1>
1>  A::aa this adjustor: 0
1>
1>
1>  class B    size(16):
1>      +---
1>   0    | {vfptr}
1>   4    | {vbptr}
1>   8    | j
1>        | <alignment member> (size=1)
1>      +---
1>      +--- (virtual base A)
1>  12    | {vfptr}
1>      +---
1>
1>  B::[email protected]@:
1>      | &B_meta
1>      |  0
1>   0    | &B::bb
1>
1>  B::[email protected]:
1>   0    | -4
1>   1    | 8 (Bd(B+4)A)
1>
1>  B::[email protected]@:
1>      | -12
1>   0    | &A::aa
1>
1>  B::bb this adjustor: 0
1>
1>  vbi:       class  offset o.vbptr  o.vbte fVtorDisp
1>                 A      12       4       4 0
1>
1>
1>  class C    size(16):
1>      +---
1>   0    | {vfptr}
1>   4    | {vbptr}
1>   8    | i
1>        | <alignment member> (size=1)
1>      +---
1>      +--- (virtual base A)
1>  12    | {vfptr}
1>      +---
1>
1>  C::[email protected]@:
1>      | &C_meta
1>      |  0
1>   0    | &C::cc
1>
1>  C::[email protected]:
1>   0    | -4
1>   1    | 8 (Cd(C+4)A)
1>
1>  C::[email protected]@:
1>      | -12
1>   0    | &A::aa
1>
1>  C::cc this adjustor: 0
1>
1>  vbi:       class  offset o.vbptr  o.vbte fVtorDisp
1>                 A      12       4       4 0
1>
1>
1>  class C1    size(8):
1>      +---
1>      | +--- (base class A)
1>   0    | | {vfptr}
1>      | +---
1>   4    | i1
1>        | <alignment member> (size=1)
1>      +---
1>
1>  C1::[email protected]:
1>      | &C1_meta
1>      |  0
1>   0    | &A::aa
1>   1    | &C1::cc1
1>
1>  C1::cc1 this adjustor: 0
1>
1>
1>  class D    size(20):
1>      +---
1>      | +--- (base class C)
1>   0    | | {vfptr}
1>   4    | | {vbptr}
1>   8    | | i
1>        | | <alignment member> (size=1)
1>      | +---
1>  12    | d
1>        | <alignment member> (size=1)
1>      +---
1>      +--- (virtual base A)
1>  16    | {vfptr}
1>      +---
1>
1>  D::[email protected]@:
1>      | &D_meta
1>      |  0
1>   0    | &C::cc
1>   1    | &D::dd
1>
1>  D::[email protected]:
1>   0    | -4
1>   1    | 12 (Dd(C+4)A)
1>
1>  D::[email protected]@:
1>      | -16
1>   0    | &A::aa
1>
1>  D::dd this adjustor: 0
1>
1>  vbi:       class  offset o.vbptr  o.vbte fVtorDisp
1>                 A      16       4       4 0
1>
1>
1>  class D1    size(12):
1>      +---
1>      | +--- (base class C1)
1>      | | +--- (base class A)
1>   0    | | | {vfptr}
1>      | | +---
1>   4    | | i1
1>        | | <alignment member> (size=1)
1>      | +---
1>   8    | d1
1>        | <alignment member> (size=1)
1>      +---
1>
1>  D1::[email protected]:
1>      | &D1_meta
1>      |  0
1>   0    | &A::aa
1>   1    | &C1::cc1
1>   2    | &D1::dd1
1>
1>  D1::dd1 this adjustor: 0
1>
1>
1>  class E    size(28):
1>      +---
1>   0    | {vfptr}
1>   4    | {vbptr}
1>   8    | e
1>        | <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    | i
1>        | <alignment member> (size=1)
1>      +---
1>
1>  E::[email protected]:
1>      | &E_meta
1>      |  0
1>   0    | &E::ee
1>
1>  E::[email protected]@:
1>   0    | -4
1>   1    | 8 (Ed(E+4)A)
1>   2    | 12 (Ed(E+4)C)
1>
1>  E::[email protected]@:
1>      | -12
1>   0    | &A::aa
1>
1>  E::[email protected]@:
1>      | -16
1>   0    | &C::cc
1>
1>  E::[email protected]@:
1>   0    | -4
1>   1    | -8 (Ed(C+4)A)
1>
1>  E::ee this adjustor: 0
1>
1>  vbi:       class  offset o.vbptr  o.vbte fVtorDisp
1>                 A      12       4       4 0
1>                 C      16       4       8 0
1>
1>
1>  class E1    size(20):
1>      +---
1>   0    | {vfptr}
1>   4    | {vbptr}
1>   8    | e1
1>        | <alignment member> (size=1)
1>      +---
1>      +--- (virtual base C1)
1>      | +--- (base class A)
1>  12    | | {vfptr}
1>      | +---
1>  16    | i1
1>        | <alignment member> (size=1)
1>      +---
1>
1>  E1::[email protected]@:
1>      | &E1_meta
1>      |  0
1>   0    | &E1::ee1
1>
1>  E1::[email protected]:
1>   0    | -4
1>   1    | 8 (E1d(E1+4)C1)
1>
1>  E1::[email protected]@:
1>      | -12
1>   0    | &A::aa
1>   1    | &C1::cc1
1>
1>  E1::ee1 this adjustor: 0
1>
1>  vbi:       class  offset o.vbptr  o.vbte fVtorDisp
1>                C1      12       4       4 0
1>
1>
1>  class F    size(32):
1>      +---
1>      | +--- (base class C)
1>   0    | | {vfptr}
1>   4    | | {vbptr}
1>   8    | | i
1>        | | <alignment member> (size=1)
1>      | +---
1>  12    | f
1>        | <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    | j
1>        | <alignment member> (size=1)
1>      +---
1>
1>  F::[email protected]@:
1>      | &F_meta
1>      |  0
1>   0    | &C::cc
1>   1    | &F::ff
1>
1>  F::[email protected]@:
1>   0    | -4
1>   1    | 12 (Fd(C+4)A)
1>   2    | 16 (Fd(F+4)B)
1>
1>  F::[email protected]@:
1>      | -16
1>   0    | &A::aa
1>
1>  F::[email protected]@:
1>      | -20
1>   0    | &B::bb
1>
1>  F::[email protected]@:
1>   0    | -4
1>   1    | -8 (Fd(B+4)A)
1>
1>  F::ff this adjustor: 0
1>
1>  vbi:       class  offset o.vbptr  o.vbte fVtorDisp
1>                 A      16       4       4 0
1>                 B      20       4       8 0
1>
1>
1>  class F1    size(32):
1>      +---
1>      | +--- (base class B)
1>   0    | | {vfptr}
1>   4    | | {vbptr}
1>   8    | | j
1>        | | <alignment member> (size=1)
1>      | +---
1>  12    | f1
1>        | <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    | i
1>        | <alignment member> (size=1)
1>      +---
1>
1>  F1::[email protected]@:
1>      | &F1_meta
1>      |  0
1>   0    | &B::bb
1>   1    | &F1::ff1
1>
1>  F1::[email protected]@:
1>   0    | -4
1>   1    | 12 (F1d(B+4)A)
1>   2    | 16 (F1d(F1+4)C)
1>
1>  F1::[email protected]@:
1>      | -16
1>   0    | &A::aa
1>
1>  F1::[email protected]@:
1>      | -20
1>   0    | &C::cc
1>
1>  F1::[email protected]@:
1>   0    | -4
1>   1    | -8 (F1d(C+4)A)
1>
1>  F1::ff1 this adjustor: 0
1>
1>  vbi:       class  offset o.vbptr  o.vbte fVtorDisp
1>                 A      16       4       4 0
1>                 C      20       4       8 0
1>
1>
1>  class G    size(40):
1>      +---
1>   0    | {vfptr}
1>   4    | {vbptr}
1>   8    | g
1>        | <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    | i
1>        | <alignment member> (size=1)
1>      +---
1>      +--- (virtual base E)
1>  28    | {vfptr}
1>  32    | {vbptr}
1>  36    | e
1>        | <alignment member> (size=1)
1>      +---
1>
1>  G::[email protected]@:
1>      | &G_meta
1>      |  0
1>   0    | &G::gg
1>
1>  G::[email protected]:
1>   0    | -4
1>   1    | 8 (Gd(G+4)A)
1>   2    | 12 (Gd(G+4)C)
1>   3    | 24 (Gd(G+4)E)
1>
1>  G::[email protected]@:
1>      | -12
1>   0    | &A::aa
1>
1>  G::[email protected]@:
1>      | -16
1>   0    | &C::cc
1>
1>  G::[email protected]@:
1>   0    | -4
1>   1    | -8 (Gd(C+4)A)
1>
1>  G::[email protected]@:
1>      | -28
1>   0    | &E::ee
1>
1>  G::[email protected]@:
1>   0    | -4
1>   1    | -20 (Gd(E+4)A)
1>   2    | -16 (Gd(E+4)C)
1>
1>  G::gg this adjustor: 0
1>
1>  vbi:       class  offset o.vbptr  o.vbte fVtorDisp
1>                 A      12       4       4 0
1>                 C      16       4       8 0
1>                 E      28       4      12 0
1>
1>
1>  class H    size(40):
1>      +---
1>   0    | {vfptr}
1>   4    | {vbptr}
1>   8    | h
1>        | <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    | i
1>        | <alignment member> (size=1)
1>      +---
1>      +--- (virtual base E)
1>  28    | {vfptr}
1>  32    | {vbptr}
1>  36    | e
1>        | <alignment member> (size=1)
1>      +---
1>
1>  H::[email protected]@:
1>      | &H_meta
1>      |  0
1>   0    | &H::hh
1>
1>  H::[email protected]:
1>   0    | -4
1>   1    | 8 (Hd(H+4)A)
1>   2    | 12 (Hd(H+4)C)
1>   3    | 24 (Hd(H+4)E)
1>
1>  H::[email protected]@:
1>      | -12
1>   0    | &A::aa
1>
1>  H::[email protected]@:
1>      | -16
1>   0    | &C::cc
1>
1>  H::[email protected]@:
1>   0    | -4
1>   1    | -8 (Hd(C+4)A)
1>
1>  H::[email protected]@:
1>      | -28
1>   0    | &E::ee
1>
1>  H::[email protected]@:
1>   0    | -4
1>   1    | -20 (Hd(E+4)A)
1>   2    | -16 (Hd(E+4)C)
1>
1>  H::hh this adjustor: 0
1>
1>  vbi:       class  offset o.vbptr  o.vbte fVtorDisp
1>                 A      12       4       4 0
1>                 C      16       4       8 0
1>                 E      28       4      12 0
1>
1>
1>  class H1    size(40):
1>      +---
1>      | +--- (base class E)
1>   0    | | {vfptr}
1>   4    | | {vbptr}
1>   8    | | e
1>        | | <alignment member> (size=1)
1>      | +---
1>      | +--- (base class C1)
1>      | | +--- (base class A)
1>  12    | | | {vfptr}
1>      | | +---
1>  16    | | i1
1>        | | <alignment member> (size=1)
1>      | +---
1>  20    | h1
1>        | <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    | i
1>        | <alignment member> (size=1)
1>      +---
1>
1>  H1::[email protected]@:
1>      | &H1_meta
1>      |  0
1>   0    | &E::ee
1>   1    | &H1::hh1
1>
1>  H1::[email protected]@:
1>      | -12
1>   0    | &A::aa
1>   1    | &C1::cc1
1>
1>  H1::[email protected]@:
1>   0    | -4
1>   1    | 20 (H1d(E+4)A)
1>   2    | 24 (H1d(E+4)C)
1>
1>  H1::[email protected]@:
1>      | -24
1>   0    | &A::aa
1>
1>  H1::[email protected]@:
1>      | -28
1>   0    | &C::cc
1>
1>  H1::[email protected]@:
1>   0    | -4
1>   1    | -8 (H1d(C+4)A)
1>
1>  H1::hh1 this adjustor: 0
1>
1>  vbi:       class  offset o.vbptr  o.vbte fVtorDisp
1>                 A      24       4       4 0
1>                 C      28       4       8 0
  总结出单继承内存分布大致如下:
  1. 普通继承情况下,先父类元素后子类元素,若父类元素本身也是从某个爷爷类继承而来:父类是虚继承而来,则先父后子再爷爷(其实这个分布是满足规则2的),即爷爷放在最后;父类是普通继承而来,先爷爷后父再子,即爷爷放在前面。
  2. 虚继承情况下,先子类元素后父类元素,如果父类元素本身也是从某个爷爷类继承(不论是虚继承还是普通继承)而来,则父类由类的深到浅依次分布(先爷爷后父,爷爷在子和父之间)。

  多继承的内存分布情况如下:

  1. 虚继承和普通继承同时存在的情况下,先进行普通继承,再进行虚继承。
  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(){};
};

 

C++ 继承之虚继承与普通继承的内存分布,布布扣,bubuko.com

时间: 2024-10-20 03:20:53

C++ 继承之虚继承与普通继承的内存分布的相关文章

多重继承,虚继承,MI继承中虚继承中构造函数的调用情况

先来测试一些普通的多重继承.其实这个是显而易见的. 测试代码: [cpp] view plain copy print? //测试多重继承中派生类的构造函数的调用顺序何时调用 //Fedora20 gcc version=4.8.2 #include <iostream> using namespace std; class base { public: base() { cout<<"base created!"<<endl; } ~base()

C++ 虚函数表解析 继承

C++ 虚函数表解析 陈皓 http://blog.csdn.net/haoel 前言 C++中的虚函数的作用主要是实现了多态的机制.关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数.这种技术可以让父类的指针有"多种形态",这是一种泛型技术.所谓泛型技术,说白了就是试图使用不变的代码来实现可变的算法.比如:模板技术,RTTI技术,虚函数技术,要么是试图做到在编译时决议,要么试图做到运行时决议. 关于虚函数的使用方法,我在这里不做过多的阐述

c/c++: c++继承 内存分布 虚表 虚指针 (转)

http://www.cnblogs.com/DylanWind/archive/2009/01/12/1373919.html 前部分原创,转载请注明出处,谢谢! class Base { public:  int m_base; }; class DerivedA: public Base { public:  int m_derivedA; }; class DerivedB: public Base { public:  int m_derivedB; }; class DerivedC

【整理】C++虚函数及其继承、虚继承类大小

参考文章: http://blog.chinaunix.net/uid-25132162-id-1564955.html http://blog.csdn.net/haoel/article/details/1948051/ 一.虚函数与继承 1.空类,空类单继承,空类多继承的sizeof #include <iostream> using namespace std; class Base1 { }; class Base2 { }; class Derived1:public Base1

[GeekBand] C++继承关系下虚函数内存分布

本文参考文献:GeekBand课堂内容,授课老师:侯捷 :深度探索C++对象模型(侯捷译) :网络资料,如:http://blog.csdn.net/sanfengshou/article/details/4574604 说明:由于条件限制,仅测试了Windows平台下的VS2013 IDE.其余平台结果可能不同,但原理都类似.建议读者自己在其他平台进行测试. 1.什么是虚函数? 虚函数是类的非静态成员函数,在类中的基本形式如下:virtual 函数返回值类型 虚函数名(形参表) 如:virtu

类多继承及虚继承探研

多继承产生的问题 #include <iostream> using namespace std; // 多继承产生的问题:如果一个继承的多继承有同一个父类, // 则父类的构造函数会被调用两次 ////////////////////////////////////////////////////////////////////////// // 多继承,多基类混乱的问题 // 以下代码的结果 /* 总类 A 构造函数被调用... 类 A1 构造函数被调用... 总类 A 构造函数被调用..

C++ 多继承和虚继承的内存布局(Memory Layout for Multiple and Virtual Inheritance)

警告. 本文有点技术难度,需要读者了解C++和一些汇编语言知识. 在本文中,我们解释由gcc编译器实现多继承和虚继承的对象的布局.虽然在理想的C++程序中不需要知道这些编译器内部细节,但不幸的是多重继承(特别是虚拟继承)的实现方式有各种各样的不太明确的结论(尤其是,关于向下转型指针,使用指向指针的指针,还有虚拟基类的构造方法的调用命令). 如果你了解多重继承是如何实现的,你就能预见到这些结论并运用到你的代码中.而且,如果你关心性能,理解虚拟继承的开销也是非常有用的.最后,这很有趣. :-) 多重

&lt;转&gt;C++继承中虚函数的使用

转自:http://blog.csdn.net/itolfn/article/details/7412364 一:继承中的指针问题. 1. 指向基类的指针可以指向派生类对象,当基类指针指向派生类对象时,这种指针只能访问派生对象从基类继承 而来的那些成员,不能访问子类特有的元素 ,除非应用强类型转换,例如有基类B和从B派生的子类D,则B *p;D  dd; p=&dd;是可以的,指针p只能访问从基类派生而来的成员,不能访问派生类D特有的成员.因为基类不 知道派生类中的这些成员. 2. 不能使派生类

虚继承和虚函数继承

虚继承主要用于菱形 形式的继承形式 虚继承是为了在多继承的时候避免引发歧义, 比如类A有个就是a,B继承了A,C也继承了A,当D多继承B,C时,就会有歧义产生了,所以要使用虚拟继承避免重复拷贝. 虚函数继承是解决多态性的,当用基类指针指向派生类对象的时候,基类指针调用虚函数的时候会自动调用派生类的虚函数,这就是多态性,也叫动态编联 虚函数继承: class A { virtual void fun() {cout < <'A' < <endl;}; }; class B : pub