C++ 对象模型 笔记一

以下均以Visual Studio 2015 /d1 reportSingleClass输出结果分析

0 基础内存分布

0.0 所有non-static成员数据均分布在Object内;
0.1 所有non-static、static、virtual成员方法均分布在Object外;
0.2 当存在vfptr时,vfptr的第0项为typeinfo信息;
0.3 需要时,将会被填充字节进行内存对齐;

1 加上继承

1.0 单继承

1.0.0 若基类存在虚方法,则Object包含vfptr(virtual function table pointer),此vfptr为基类的vfptr,反之则无;
1.0.1 若派生类复写了基类的虚方法,则vfptr中基类虚方法将被覆盖;

2.0 多继承

1.0.0 若多个基类存在虚方法,则Object包含多个vfptr分别对应各个基类;其中,派生类以继承列表中第一个基类的vfptr作为自己的vfptr(此处以Vistual Studio为准);
1.0.1 1.0.0中所描述,若派生类复写了多个基类中同名的虚方法,则对应各基类的虚方法都将被定向到派生类所复写的方法;Visual Studio依然以第一个基类的vfptr作为派生类的vfptr,其他基类vfptr中该同名方法后将以goto标记到派生类vfptr中的复写方法;如下:

1>  class CDerived  size(12):
1>      +---
1>   0  | +--- (base class CBase)
1>   0  | | {vfptr}
1>   4  | | m_base
1>      | +---
1>   8  | +--- (base class COther)
1>   8  | | {vfptr}
1>      | +---
1>      +---
1>
1>  CDerived::$vftable@CBase@:
1>      | &CDerived_meta
1>      |  0
1>   0  | &CDerived::display
1>
1>  CDerived::$vftable@COther@:
1>      | -8
1>   0  | &thunk: this-=8; goto CDerived::display
1>
1>  CDerived::display this adjustor: 0

1.0.2 基类在内存中的顺序与继承列表一致;

3.0 virtual继承

3.0.0 单独virtual 继承
A. 派生类Object此时不再包含虚基类的任何成员,仅用vbptr(virtual base table pointer)指向一个虚基类表,其中存放虚基类的地址;
B. 若此时,派生类此时复写了虚基类方法,则复写的方法仍然覆盖到基类的vfptr中;
C. 若此时,派生类拥有自己独立的虚方法,则Object将拥有独立于第一个基类的vfptr
3.0.1 virtual + 普通继承
A. 此时,派生类将拥有普通基类子对象、vbptr、自身的成员;
B. 此时,派生类若无自己独立的虚方法,则以继承列表中第一个普通基类的vfptr作为自己的vfptr(看派生类的typeinfo信息在哪个vfptr中);
C. 由B所述,若派生类此时拥有自己独立的虚方法时,仍以继承列表中第一个普通基类的vfptr作为自身的vfptr,而不再如3.0.0:C中所述将拥有自己独立的vfptr;如:

1>  class CDerived  size(16):
1>      +---
1>   0  | +--- (base class COther)
1>   0  | | {vfptr}
1>      | +---
1>   4  | {vbptr}
1>      +---
1>      +--- (virtual base CBase)
1>   8  | {vfptr}
1>  12  | m_base
1>      +---
1>
1>  CDerived::$vftable@COther@:
1>      | &CDerived_meta
1>      |  0
1>   0  | &COther::display
1>   1  | &CDerived::displayA
1>
1>  CDerived::$vbtable@:
1>   0  | -4
1>   1  | 4 (CDerivedd(CDerived+4)CBase)
1>
1>  CDerived::$vftable@CBase@:
1>      | -8
1>   0  | &CBase::display
1>
1>  CDerived::displayA this adjustor: 0
1>  vbi:       class  offset o.vbptr  o.vbte fVtorDisp
1>             CBase       8       4       4 0

D. 若派生类复写了,普通基类与虚基类相同签名的虚方法,则以第一个普通基类的vfptr为准,并将虚基类的该方法定向到该处;如:

class CDerived  size(16):
1>      +---
1>   0  | +--- (base class COther)
1>   0  | | {vfptr}
1>      | +---
1>   4  | {vbptr}
1>      +---
1>      +--- (virtual base CBase)
1>   8  | {vfptr}
1>  12  | m_base
1>      +---
1>
1>  CDerived::$vftable@COther@:
1>      | &CDerived_meta
1>      |  0
1>   0  | &CDerived::display
1>
1>  CDerived::$vbtable@:
1>   0  | -4
1>   1  | 4 (CDerivedd(CDerived+4)CBase)
1>
1>  CDerived::$vftable@CBase@:
1>      | -8
1>   0  | &thunk: this-=8; goto CDerived::display
1>
1>  CDerived::display this adjustor: 0
1>  vbi:       class  offset o.vbptr  o.vbte fVtorDisp
1>             CBase       8       4       4 0

3.0.2 多virtual继承
A. 派生类将拥有自身成员以及一个vbptr;
B. Virutal base table pointer 中的基类在内存中按继承列表顺序;
C. 若此时,派生类拥有自己独立的虚方法,则派生类将拥有自己独立的vfptr;
D. 若此时,派生类复写了基类相同的签名方法,则派生类将根据继承列表顺序为准,复写虚基类的vfptr,其他虚基类的vfptr将以goto重定向到该处;
E. 若派生类同时满足C、D描述中的条件,则各条件均遵守其结果:独立虚方法,将使派生类拥有自己的vfptr;而复写的方法仍按D所述。如:

1>  class CDerived  size(20):
1>      +---
1>   0  | {vfptr}
1>   4  | {vbptr}
1>      +---
1>      +--- (virtual base CBase)
1>   8  | {vfptr}
1>  12  | m_base
1>      +---
1>      +--- (virtual base COther)
1>  16  | {vfptr}
1>      +---
1>
1>  CDerived::$vftable@CDerived@:
1>      | &CDerived_meta
1>      |  0
1>   0  | &CDerived::forTest
1>
1>  CDerived::$vbtable@:
1>   0  | -4
1>   1  | 4 (CDerivedd(CDerived+4)CBase)
1>   2  | 12 (CDerivedd(CDerived+4)COther)
1>
1>  CDerived::$vftable@CBase@:
1>      | -8
1>   0  | &CDerived::display
1>
1>  CDerived::$vftable@COther@:
1>      | -16
1>   0  | &thunk: this-=8; goto CDerived::display
1>
1>  CDerived::forTest this adjustor: 0
1>  CDerived::display this adjustor: 8
1>  vbi:       class  offset o.vbptr  o.vbte fVtorDisp
1>             CBase       8       4       4 0
1>            COther      16       4       8 0
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值