设为首页 加入收藏

TOP

12.4 菱形继承(2)
2013-10-07 14:30:45 来源: 作者: 【 】 浏览:61
Tags:12.4 菱形 继承

12.4 菱形继承(2)

代码清单12-13中一共定义了4个类,分别为CFurniture、CSofa、CBed和CSofaBed。CFurniture为祖父类,从CFurniture类中派生了两个子类:CSofa与CBed,它们在继承时使用了virtual的方式,即虚继承。

使用虚继承可以避免共同派生出的子类产生多义性的错误。那么,为什么要将virtual加在两个父类上而不是它们共同派生的子类呢?这个问题与现实世界中动物的繁衍很相似,例如,熊猫在繁衍时要避免具有血缘关系的雄性与雌性“近亲繁殖”,因为“近亲繁殖”的结果会使繁殖出的后代出现基因重叠的问题,从而造成残缺现象。类CBed与类CSofa就如同是一对兄妹,它们的父亲为CSofaBed,当类CBed与类CSofa“近亲结合”后“生下”存在基因问题的子类CSofaBed时,也会存在基因重叠问题,因此通过虚继承来防止这个问题的发生。接下来介绍菱形结构中子类CSofaBed的对象在内存中是如何存放的,如图12-13所示。

 
图12-13 CSofaBed的内存结构
图12-13中显示了SofaBed在内存中的信息,初步观察内存中保存的数据可得知,有些数据类似地址值。这些地址值都有哪些含义呢?图12-14对各个地址数据进行了注解。
 
图12-14 CSofaBed内存结构的注解

通过图12-14虽然可以知道各个数据所具有的含义,但是还存在一些模糊不清的数据无法理解,如CSofaBed_vt(new)和vt_offset,它们又都代表着什么呢?带着这个疑问,我们将代码清单12-13转换成汇编代码,如代码清单12-14所示。

代码清单12-14 菱形结构的虚表指针转换过程

  1. // C++(www.cppentry.com)源码对比,加入了父类指针的转换代码  
  2. void main(int argc, char* argv[]){  
  3.     CSofaBed SofaBed;  
  4.     CFurniture * pFurniture = &SofaBed;         // 转换成祖父类指针  
  5.     CSofa * pSofa = &SofaBed;               // 转换成父类指针  
  6.     CBed * pBed = &SofaBed;             // 转换成父类指针  
  7. }  
  8.  
  9. // C++(www.cppentry.com)源码与对应汇编代码讲解  
  10. void main(int argc, char* argv[]){  
  11.     CSofaBed  SofaBed;  
  12. 0040F718    push    1    ; 是否构造祖父类的标志,TRUE表示构造,FALSE表示不构造  
  13. 0040F71A    lea     ecx,[ebp-28h]       ; 传入对象的首地址作为this指针  
  14. 0040F71D        call    @ILT+10(CSofaBed::CSofaBed) (0040100f)  ; 调用构造函数  
  15.     CFurniture * pFurniture = &SofaBed;  
  16. 0040F722    lea     eax,[ebp-28h]           ; 获取对象的首地址  
  17. 0040F725    test    eax,eax             ; 检查代码  
  18. 0040F727    jne     main+32h (0040f732) ; 跳转到0x0040f732  
  19. 0040F729    mov     dword ptr [ebp-38h],0  
  20. 0040F730    jmp     main+3Fh (0040f73f)  
  21.     ;  取出对象的第二项数据vt_offset,此地址指向的数据如图12-14所示  
  22. 0040F732    mov     ecx,dword ptr [ebp-24h]  
  23. 0040F735    mov edx,dword ptr [ecx+4]   ; 取出偏移值后存入edx中  
  24. 0040F738    lea     eax,[ebp+edx-24h]       ; 得到祖父类数据的所在地址  
  25. 0040F73C    mov     dword ptr [ebp-38h],eax ; 利用中间变量保存祖父类的首地址  
  26. 0040F73F    mov     ecx,dword ptr [ebp-38h]  
  27. 0040F742    mov     dword ptr [ebp-2Ch],ecx ; 赋值pFurniture  
  28.     CSofa * pSofa = &SofaBed;  
  29. 0040F745        lea     edx,[ebp-28h]   ; 直接转换SofaBed对象的首地址为父类CSofa的指针  
  30. 0040F748    mov     dword ptr [ebp-30h],edx  
  31.     CBed * pBed = &SofaBed;  
  32. 0040F74B        lea     eax,[ebp-28h]           ; 获取对象SofaBed的首地址  
  33. 0040F74E    test    eax,eax         ; 地址检查  
  34. 0040F750    je      main+5Ah (0040f75a)  
  35. 0040F752    lea     ecx,[ebp-1Ch]       ; 获取第二个CSofaBed_vt(new)指针  
  36. 0040F755    mov     dword ptr [ebp-3Ch],ecx  
  37. 0040F758    jmp     main+61h (0040f761)  
  38. 0040F75A    mov     dword ptr [ebp-3Ch],0  
  39. 0040F761    mov     edx,dword ptr [ebp-3Ch]  
  40. 0040F764    mov     dword ptr [ebp-34h],edx ; 保存转换后的SofaBed地址到pSofa中  

】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇12.4 菱形继承(3) 下一篇12.4 菱形继承(1)

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: