设为首页 加入收藏

TOP

12.1 识别类和类之间的关系(3)
2013-10-07 14:30:59 来源: 作者: 【 】 浏览:51
Tags:12.1 识别 类和 之间 关系

12.1 识别类和类之间的关系(3)

我们先看看正确的情况,如代码清单12-3所示。

代码清单12-3 子类调用父类函数—Debug版

  1. // ShowNumber源码对照代码清单12-1  
  2. void ShowNumber(int nNumber){  
  3.     ; 函数入口代码略  
  4. 0040ECC9    pop         ecx  
  5. 0040ECCA    mov         dword ptr [ebp-4],ecx   ; [ebp-4]中保留了this指针  
  6. 41:           SetNumber (nNumber);  
  7. 0040ECCD    mov     eax,dword ptr [ebp+8]   ; 访问参数nNumber并保存到eax中  
  8. 0040ECD0    push        eax  
  9.    ;由于this指针同时也是对象中父类部分的首地址,因此在调用父类成员函数时,this指针的值和子类  
  10.    ;对象等同  
  11. 0040ECD1   mov          ecx,dword ptr [ebp-4]  
  12. 0040ECD4   call         @ILT+45(CBase::SetNumber) (00401032)  
  13. 42:           m_nDervie = nNumber + 1;  
  14. 0040ECD9   mov         ecx,dword ptr [ebp+8]  
  15. 0040ECDC   add         ecx,1    ; 将参数值加1  
  16. 0040ECDF   mov         edx,dword ptr [ebp-4]    ; edx获得this指针  
  17.     ; 参考内存结构,edx+4是子类成员m_nDervie的地址  
  18. 0040ECE2   mov         dword ptr [edx+4],ecx  
  19. 43:           printf("%d\r\n", GetNumber());  
  20. 0040ECE5   mov         ecx,dword ptr [ebp-4]  
  21. 0040ECE8   call        @ILT+60(CBase::GetNumber) (00401041)  
  22. 0040ECED   push        eax  
  23. 0040ECEE   push        offset string "%d\r\n" (0042501c)  
  24. 0040ECF3   call        printf (004012b0)  
  25. 0040ECF8   add         esp,8  
  26. 44:           printf("%d\r\n", m_nDervie);  
  27. 0040ECFB   mov         eax,dword ptr [ebp-4]    ; eax获得this指针  
  28.     ; 参考内存结构,eax+4是子类成员m_nDervie的地址  
  29. 0040ECFE   mov         ecx,dword ptr [eax+4]  
  30. 0040ED01   push        ecx  
  31. 0040ED02   push        offset string "%d\r\n" (0042501c)  
  32. 0040ED07   call        printf (004012b0)  
  33. 0040ED0C   add         esp,8  
  34.     ; 函数退出代码略  
  35. }  
  36.  
  37. ; 父类成员函数SetNumber分析  
  38. void SetNumber(int nNumber){  
  39. 00401199    pop     ecx         ; 还原this指针  
  40. 0040119A    mov     dword ptr [ebp-4],ecx   ; [ebp-4]中保留了this指针  
  41.     m_nBase = nNumber;  
  42. 0040119D    mov     eax,dword ptr [ebp-4]   ; eax得到this指针  
  43. 004011A0    mov     ecx,dword ptr [ebp+8]   ; ecx得到参数  
  44.     ; 这里的[eax]相当于[this+0],参考内存结构,是父类成员m_nBase  
  45. 004011A3    mov     dword ptr [eax],ecx  

父类中成员函数SetNumber在子类中并没有被定义,但根据派生关系,子类中可以使用父类的公有函数。编译器是如何实现正确匹配的呢?

如使用对象或对象的指针调用成员函数,编译器可根据对象所属作用域来使用“名称粉碎法”①,以实现正确匹配。在成员函数中调用其他成员函数时,可匹配当前作用域。

在调用父类成员函数时,虽然其this指针传递的是子类对象的首地址,但是在父类成员函数中可以成功寻址到父类中的数据。回想之前提及的对象内存布局,父类数据成员被排列在地址最前端,之后是子类数据成员。ShowNumber运行过程中的内存信息如图12-1所示。

 
图12-1 子类对象Dervie的内存布局
这时,首地址处为父类数据成员,而父类中的成员函数SetNumber在寻址此数据成员时,会将首地址的4字节数据作为数据成员m_nBase。由此可见,父类数据成员被排列在最前端的目的是为了在添加派生类后方便子类使用父类中的成员数据,并且可以将子类指针当父类指针使用。按照继承顺序依次排列各个数据成员,这样一来,不管是操作子类对象还是父类对象,只要确认了对象的首地址,对父类成员数据的偏移量而言都是一样的。对子类对象而言,使用父类指针或者子类指针都可以正确访问其父类数据。反之,如果使用一个子类对象的指针去访问父类对象,则存在越界访问的危险,如代码清单12-4所示。
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇12.1 识别类和类之间的关系(4) 下一篇12.1 识别类和类之间的关系(2)

评论

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