设为首页 加入收藏

TOP

12.2 多重继承(3)
2013-10-07 14:30:41 来源: 作者: 【 】 浏览:59
Tags:12.2 多重 继承

12.2 多重继承(3)

在代码清单12-10中,在转换CBed指针时,会调整首地址并跳过第一个父类所占用的空间。这样一来,当使用父类CBed的指针访问CBed中实现的虚函数时,就不会错误地寻址到继承自CSofa类的成员变量。

了解了多重继承中子类的构造函数,以及父类指针的转换过程后,接下来通过分析代码清单12-11来学习多重继承中子类对象的析构过程。

代码清单12-11 多重继承的类对象析构函数—Debug版

  1. ; 子类析构函数的实现过程  
  2. virtual ~CSofaBed(){                    // 沙发床类的虚析构函数  
  3.     ; 部分代码略  
  4. 0040170E    pop     ecx             ; 还原this指针  
  5. 0040170F    mov     dword ptr [ebp-10h],ecx  
  6. 00401712    mov     eax,dword ptr [ebp-10h]  
  7.     ; 将两个虚表指针设置为各个父类的虚表首地址  
  8. 00401715    mov     dword ptr [eax],offset CSofaBed::'vftable' (00426198)  
  9. 0040171B    mov     ecx,dword ptr [ebp-10h]  
  10. 0040171E    mov     dword ptr [ecx+8],offset CSofaBed::'vftable' (0042501c)  
  11. 00401725    mov     dword ptr [ebp-4],0  
  12.     ; 执行子类虚函数内的代码  
  13. printf("virtual ~CSofaBed()\r\n");  
  14. }  
  15.     ; 比较对象地址,与子类对象转为父类指针相似  
  16. 00401739    cmp     dword ptr [ebp-10h],0  ; 当this==NULL时不需调整  
  17. 0040173D    je      CSofaBed::~CSofaBed+6Ah (0040174a)  
  18. 0040173F    mov     edx,dword ptr [ebp-10h]  
  19. 00401742    add     edx,8  
  20. 00401745    mov     dword ptr [ebp-14h],edx ; 将调整后的this指针保存到[ebp-14h]  
  21. 00401748    jmp     CSofaBed::~CSofaBed+71h (00401751)  
  22. 0040174A    mov     dword ptr [ebp-14h],0  
  23. 00401751    mov     ecx,dword ptr [ebp-14h]  
  24.     ; 调用父类CBed的析构函数  
  25. 00401754    call    @ILT+75(CBed::~CBed) (00401050)  
  26. 00401759    mov     dword ptr [ebp-4],0FFFFFFFFh  
  27. 00401760    mov     ecx,dword ptr [ebp-10h]  
  28.     ; 无需转换this指针,直接调用父类CSofa的析构函数  
  29. 00401763    call    @ILT+125(CSofa::~CSofa) (00401082)  
  30. 00401768    mov     ecx,dword ptr [ebp-0Ch]  
  31. 0040176B    mov     dword ptr fs:[0],ecx  
  32.     ; 部分代码略  
  33. 00401782   ret 

代码清单12-11演示了对象SofaBed的析构过程。由于具有多个同级父类(多个同时继承的父类),因此在子类中产生了多个虚表指针。在对父类进行析构时,需要设置this指针,用于调用父类的析构函数。由于具有多个父类,当在析构的过程中调用各个父类的析构函数时,传递的首地址将有所不同,编译器会根据每个父类在对象中占用的空间位置,对应地传入各个父类部分的首地址作为this指针。

在Debug版下,由于侧重调试功能,因此使用了两个临时变量来分别保存两个this指针,它们对应的地址分别为两个虚表指针的首地址。在Release版下,虽然会进行优化,但原理不变,子类析构函数调用父类的析构函数时,仍然会传入在对象中父类对应的地址,当做this指针。

前面讲解了多重继承中子类对象的生成与销毁过程,以及在内存中的分布情况,对比单继承类,两者特征总结如下:

单继承类

在类对象占用的内存空间中,只保存一份虚表指针。

由于只有一个虚表指针,对应的也只有一个虚表。

虚表中各项保存了类中各虚函数的首地址。

构造时先构造父类,再构造自身,并且只调用一次父类构造函数。

析构时先析构自身,再析构父类,并且只调用一次父类析构函数。

多重继承类

在类对象所占用的内存空间中,根据继承父类的个数保存对应的虚表指针。

根据所保存的虚表指针的个数,对应产生相应个数的虚表。

转换父类指针时,需要跳转到对象的首地址。

构造时需要调用多个父类构造函数。

构造时先构造继承列表中第一个父类,然后依次调用到最后一个继承的父类构造函数。

析构时先析构自身,然后以与构造函数相反的顺序调用所有父类的析构函数。

当对象作为成员时,整个类对象的内存结构和多重继承很相似。当类中无虚函数时,整个类对象内存结构和多重继承完全一样,可酌情还原;当父类或成员对象存在虚函数时,通过观察虚表指针的位置和构造函数、析构函数中填写虚表指针的数目及目标地址,来还原继承或成员关系。

在对象模型的还原过程中,可根据以上特性识别出继承关系。对于有虚函数的情况,可利用虚表的初始化,使用IDA中的引用参考进行识别还原。引用参考的使用请回顾第11章的相关内容。

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

评论

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