用汇编的眼光看C++(之类继承)

【 声明:版权所有,欢迎转载,请勿用于商业用途。  联系信箱:feixiaoxing @163.com】


    继承是类的一个基本属性,可是在类的继承过程中,函数是怎么初始化?怎么析构的呢?我们不妨看看下面这样的一段代码?

  1. class employee  
  2. {  
  3. public:  
  4.     employee() { printf("employee()!\n");}  
  5.     ~employee() { printf("~employee()!\n");}  
  6. };  
  7.   
  8. class manager : public employee  
  9. {  
  10. public:  
  11.     manager() { printf("manager()!\n");}  
  12.     ~manager() {  printf("~maneger()!\n");}  
  13. };  
    看到上面的代码,相信大家也明白了,我们定义了这样一个类。基类是empoyee,继承类是manager。我们看到manager是一种特殊的employee,那么在内存构建和析构的时候函数又是怎么安排的呢?

  1. 74:       manager m;  
  2. 00401268   lea         ecx,[ebp-4]  
  3. 0040126B   call        @ILT+60(manager::manager) (00401041)  
  4. 75:   }  
  5. 00401270   lea         ecx,[ebp-4]  
  6. 00401273   call        @ILT+0(manager::~manager) (00401005)  
  7. 00401278   pop         edi  
  8. 00401279   pop         esi  
  9. 0040127A   pop         ebx  
  10. 0040127B   add         esp,44h  
  11. 0040127E   cmp         ebp,esp  
  12. 00401280   call        __chkesp (00408760)  
  13. 00401285   mov         esp,ebp  
  14. 00401287   pop         ebp  
    我们发现manager的构造和析构其实也简单。构造函数其实就是在变量出现的时候进行构造。那什么时候析构呢?也就在函数快结束的时候进行析构。下面我们可以进一步讨论在manager的构造和析构究竟是怎么做的?

  1. 65:   class manager : public employee  
  2. 66:   {  
  3. 67:   public:  
  4. 68:       manager() { printf("manager()!\n");}  
  5. 004012A0   push        ebp  
  6. 004012A1   mov         ebp,esp  
  7. 004012A3   sub         esp,44h  
  8. 004012A6   push        ebx  
  9. 004012A7   push        esi  
  10. 004012A8   push        edi  
  11. 004012A9   push        ecx  
  12. 004012AA   lea         edi,[ebp-44h]  
  13. 004012AD   mov         ecx,11h  
  14. 004012B2   mov         eax,0CCCCCCCCh  
  15. 004012B7   rep stos    dword ptr [edi]  
  16. 004012B9   pop         ecx  
  17. 004012BA   mov         dword ptr [ebp-4],ecx  
  18. 004012BD   mov         ecx,dword ptr [ebp-4]  
  19. 004012C0   call        @ILT+40(employee::employee) (0040102d)  
  20. 004012C5   push        offset string "manager()!\n" (00431020)  
  21. 004012CA   call        printf (004086e0)  
  22. 004012CF   add         esp,4  
  23. 004012D2   mov         eax,dword ptr [ebp-4]  
  24. 004012D5   pop         edi  
  25. 004012D6   pop         esi  
  26. 004012D7   pop         ebx  
  27. 004012D8   add         esp,44h  
  28. 004012DB   cmp         ebp,esp  
  29. 004012DD   call        __chkesp (00408760)  
  30. 004012E2   mov         esp,ebp  
  31. 004012E4   pop         ebp  
  32. 004012E5   ret  
    我们发现,manager的构造里面添加了employee的缺省构造函数,那么析构函数呢?

  1. 69:       ~manager() {  printf("~maneger()!\n");}  
  2. 00401350   push        ebp  
  3. 00401351   mov         ebp,esp  
  4. 00401353   sub         esp,44h  
  5. 00401356   push        ebx  
  6. 00401357   push        esi  
  7. 00401358   push        edi  
  8. 00401359   push        ecx  
  9. 0040135A   lea         edi,[ebp-44h]  
  10. 0040135D   mov         ecx,11h  
  11. 00401362   mov         eax,0CCCCCCCCh  
  12. 00401367   rep stos    dword ptr [edi]  
  13. 00401369   pop         ecx  
  14. 0040136A   mov         dword ptr [ebp-4],ecx  
  15. 0040136D   push        offset string "~maneger()!\n" (00431040)  
  16. 00401372   call        printf (004086e0)  
  17. 00401377   add         esp,4  
  18. 0040137A   mov         ecx,dword ptr [ebp-4]  
  19. 0040137D   call        @ILT+5(employee::~employee) (0040100a)  
  20. 00401382   pop         edi  
  21. 00401383   pop         esi  
  22. 00401384   pop         ebx  
  23. 00401385   add         esp,44h  
  24. 00401388   cmp         ebp,esp  
  25. 0040138A   call        __chkesp (00408760)  
  26. 0040138F   mov         esp,ebp  
  27. 00401391   pop         ebp  
  28. 00401392   ret  
    我们发现,manager构造的时候employee率先构造,然后打印manager;析构的时候,恰恰相反,manager首先析构自己,然后在再调用employee的析构函数,上面的汇编代码证明了一切。

posted on 2011-09-21 11:03  四-儿  阅读(246)  评论(0编辑  收藏  举报

导航