12.4 菱形继承(3)
从代码清单12-14中的指针转换过程可以看出,vt_offset指向的内存地址中保存的数据为偏移数据,如图12-15所示,图中每个vt_offset对应的数据有两项:第一项为-4,即vt_offset所属类对应的虚表指针相对于vt_offset的偏移值;第二项保存的是父类虚表指针相对于vt_offset的偏移值。
|
| (点击查看大图)图12-15 vt_offset指向的数据 |
根据对代码清单12-13的分析可知,3个虚表指针分别为0x00425034、0x00425028、0x0042501C,它们所指向的数据如图12-16所示。
|
| (点击查看大图)图12-16 各个虚表信息 |
如图12-16所示,这三个虚表指针所指向的虚表包含了子类CSofaBed含有的虚函数。有了这些记录就可以随心所欲地将虚表指针转换成任意的父类指针。在利用父类指针访问虚函数时,只能调用子类与父类共有的虚函数,子类继承自其他父类的虚函数是无法调用的,虚表中也没有相关的记录。当子类的父类也存在多个父类时,会在图12-15所显示的表格中依次记录它们的偏移。
学习了菱形结构中子类的内存布局后,接下来分析其子类的构造函数,看看这些数据是如何产生的,如代码清单12-15所示。
代码清单12-15 菱形结构的子类构造
- CSofaBed SofaBed;
- 0040F730 push 1 ; 压入参数1
- 0040F732 lea ecx,[ebp-34h] ; 传递this指针
- 0040F735 call @ILT+10(CSofaBed::CSofaBed) (0040100f); 调用构造函数
- ; 构造函数实现
- CSofaBed(){
- ; 部分代码分析略
- 004011FE pop ecx ; 还原this指针
- 004011FF mov dword ptr [ebp-10h],ecx
- 00401202 mov dword ptr [ebp-14h],0 ; 传入构造标记
- ; 比较参数是否为0,为0则执行JE跳转,防止重复构造
- 00401209 cmp dword ptr [ebp+8],0
- 0040120D je CSofaBed::CSofaBed+6Eh (0040123e)
- 0040120F mov eax,dword ptr [ebp-10h]
- ; 设置父类CSofa中的vt_offset域
- 00401212 mov dword ptr [eax+4],offset CSofaBed::'vbtable' (00425050)
- 00401219 mov ecx,dword ptr [ebp-10h]
- ; 设置父类CBed中的vt_offset域
- 0040121C mov dword ptr [ecx+10h],offset CSofaBed::'vbtable' (00425044)
- 00401223 mov ecx,dword ptr [ebp-10h]
- 00401226 add ecx,20h ; 调整this指针
- ; 调用祖父类构造函数,祖父类为最上级,它的构造函数和无继承关系的构造函数相同,这里不予分析
- 00401229 call @ILT+45(CFurniture::CFurniture) (00401032)
- 0040122E mov edx,dword ptr [ebp-14h] ; 获取构造标记
- 00401231 or edx,1 ; 将构造标记置为1
- 00401234 mov dword ptr [ebp-14h],edx ; 修改构造标记
- 00401237 mov dword ptr [ebp-4],0
- 0040123E push 0 ; 压入0作为构造标记
- 00401240 mov ecx,dword ptr [ebp-10h] ; 获取对象首地址作为this指针
- 00401243 call @ILT+110(CSofa::CSofa) (00401073); 调用父类构造函数
- 00401248 mov dword ptr [ebp-4],1
- 0040124F push 0 ; 压入0作为构造标记
- 00401251 mov ecx,dword ptr [ebp-10h]
- 00401254 add ecx,0Ch ; 调整this指针
- 00401257 call @ILT+130(CBed::CBed) (00401087) ; 调用父类构造函数
- 0040125C mov eax,dword ptr [ebp-10h]
- ; CSofaBed对应CSofa的虚表指针
- 0040125F mov dword ptr [eax],offset CSofaBed::'vftable' (00425034)
- 00401265 mov ecx,dword ptr [ebp-10h]
- ; CSofaBed对应CBed的虚表指针
- 00401268 mov dword ptr [ecx+0Ch],offset CSofaBed::'vftable' (00425028)
- 0040126F mov edx,dword ptr [ebp-10h] ;通过this指针和vt_offset定位到祖;父类的虚表指针
- 00401272 mov eax,dword ptr [edx+4] ; vt_offset存入eax中
- 00401275 mov ecx,dword ptr [eax+4] ; 父类虚表指针相对于vt_offset的偏移存入eax中
- 00401278 mov edx,dword ptr [ebp-10h]
- ; CSofaBed对应CFurniture的虚表指针
- 0040127B mov dword ptr [edx+ecx+4],offset CSofaBed::'vftable' (0042501c)
- m_nHeight = 6;
- 00401283 mov eax,dword ptr [ebp-10h]
- 00401286 mov dword ptr [eax+1Ch],6
- }
- 004012B1 ret 4