Vb教程 Vb.net教程 Vfp教程 C/C++教程 Vc/Vc++教程 Delphi教程 Java教程 Powerbuilder
  杀毒频道 | 短信频道 | 网络电视 | 论文中心 | 学上网 | 学软件 | 网页特效 | 电脑基础 | 论坛  
  NCRE | 软考 | CET | 职称英语 | 司法考试 | 报关员 | 公务员 | CATTI | CPA考试  
  Html教程 | Css教程 | Xml教程 | Asp教程 | Asp.net | Php教程 | Jsp教程 | Linux教程 | QQ技巧  
Photoshop Illustrator ImageReady Maya教程 3D Max教程 Lightscape Coredraw教程 Authorware Autocad教程 Freehand教程
Access教程 Mysql教程 Sql server Oracle教程 Word教程 Excel教程 Powerpoint Frontpage Asp.net源码 Php源代码
Flash教程 Fireworks Dreamweaver C#教程 outlook教程 系统安装 vbscript教程 Javascript Jsp源代码 Asp源代码
您的位置:首页 >> C/C++教程 >> 正文

C++类机制的实现细节
文章来源:csdn 作者:nightsuns

 为了搞清楚VC中类的实现专门写了一个最简单的类,用来观察它的实现过程,代码如下:
   // test.cpp : Defines the entry point for the console application.
   //
  
   #include "stdafx.h"
   #include "CTest.h"
    
   int main(int argc, char* argv[])
   {
   CTest aTest;
   aTest.a(1,2);
   return 0;
   }
  
   // CTest.h: interface for the CTest class.
   //
   //////////////////////////////////////////////////////////////////////
  
   #if !defined(AFX_CTEST_H__2CCCDCFC_6C3A_48BC_9CD0_E7A8E63431D9__INCLUDED_)
   #define AFX_CTEST_H__2CCCDCFC_6C3A_48BC_9CD0_E7A8E63431D9__INCLUDED_
  
   #if _MSC_VER > 1000
   #pragma once
   #endif // _MSC_VER > 1000
  
   class CTest 
   {
   public:
   CTest();
   virtual ~CTest();
  
   public:
   void b();
   void a(int one,int two);
   };
  
   #endif // !defined(AFX_CTEST_H__2CCCDCFC_6C3A_48BC_9CD0_E7A8E63431D9__INCLUDED_)
  
  
   // CTest.cpp: implementation of the CTest class.
   //
   //////////////////////////////////////////////////////////////////////
  
   #include "stdafx.h"
   #include "CTest.h"
  
   //////////////////////////////////////////////////////////////////////
   // Construction/Destruction
   //////////////////////////////////////////////////////////////////////
  
   CTest::CTest()
   {
  
   }

  CTest::~CTest()
   {
  
   }
  
   void CTest::b()
   {
   printf("b is be called by a");
   }
  
   void CTest::a(int one,int two)
   {
   printf("call b");
   b();
   }
  
   下面是相应的反汇编代码:
   --- D:\myown\test\test.cpp ------------
     1:  // test.cpp : Defines the entry point for the console application.
2:  //
   3:
   4:  #include "stdafx.h"
   5:  #include "CTest.h"
   6:
   7:  int main(int argc, char* argv[])
   8:  {
   00401050  push    ebp
   00401051  mov     ebp,esp
   00401053  push    0FFh
   00401055  push    offset __ehhandler$_main (00410c89)
   0040105A  mov     eax,fs:[00000000]
   00401060  push    eax
   00401061  mov     dword ptr fs:[0],esp
   00401068  sub     esp,48h
   0040106B  push    ebx
   0040106C  push    esi
   0040106D  push    edi
   0040106E  lea     edi,[ebp-54h]
   00401071  mov     ecx,12h
   00401076  mov     eax,0CCCCCCCCh
   0040107B  rep stos  dword ptr [edi]
  
   9:    CTest aTest;
   0040107D  lea     ecx,[ebp-10h] //这是用来保存aTest的this指针,因为是局部变量所以是保存在[ebp-10h]中
   00401080  call    @ILT+30(CTest::CTest) (00401023) //调用aTest的构造函数,由编译器自动产生的CALL
   00401085  mov     dword ptr [ebp-4],0
  
   10:    aTest.a(1,2);
   0040108C  push    2
   0040108E  push    1
   00401090  lea     ecx,[ebp-10h] //把aTest的this指针用ecx进行传递
   00401093  call    @ILT+5(CTest::a) (0040100a) 
   11:    return 0;

 00401098  mov     dword ptr [ebp-14h],0
   0040109F  mov     dword ptr [ebp-4],0FFFFFFFFh
   004010A6  lea     ecx,[ebp-10h] //同样是this指针
   004010A9  call    @ILT+25(CTest::~CTest) (0040101e) //aTest的生存周期到了,自动调用析构函数,同样是由编译器分析之后自加上去
   004010AE  mov     eax,dword ptr [ebp-14h]
   12:  }
   004010B1  mov     ecx,dword ptr [ebp-0Ch]
   004010B4  mov     dword ptr fs:[0],ecx
   004010BB  pop     edi
   004010BC  pop     esi
   004010BD  pop     ebx
   004010BE  add     esp,54h
   004010C1  cmp     ebp,esp
   004010C3  call    __chkesp (00401670)
   004010C8  mov     esp,ebp
   004010CA  pop     ebp
   004010CB  ret
  
   下面再来分析一下VC中对函数的调用:
   可以看到上面有对三个函数的调用分别为:
   00401080  call    @ILT+30(CTest::CTest) (00401023)
   00401093  call    @ILT+5(CTest::a) (0040100a)
   004010A9  call    @ILT+25(CTest::~CTest) (0040101e)
  
   可以看到他们都跳到了以@ILT为基的一个地址去了,那么跳过去之后可以看到:
   @ILT+0(??_GCTest@@UAEPAXI@Z):
   00401005  jmp     CTest::`scalar deleting destructor' (00401130)
   @ILT+5(?a@CTest@@QAEXHH@Z):
   0040100A  jmp     CTest::a (00401230)
   @ILT+10(_main):
   0040100F  jmp     main (00401050)
   @ILT+15(?b@CTest@@QAEXXZ):
   00401014  jmp     CTest::b (004011e0)
   @ILT+20(??_GCTest@@UAEPAXI@Z):
   00401019  jmp     CTest::`scalar deleting destructor' (00401130)
   @ILT+25(??1CTest@@UAE@XZ):
   0040101E  jmp     CTest::~CTest (004011a0)
   @ILT+30(??0CTest@@QAE@XZ):
   00401023  jmp     CTest::CTest (004010f0)
  
   这个@ILT其实就是一个静态的表,它记录了一些函数的入口然后跳过去,每个跳转jmp占一个字节,然后就是一个四字节的内存地址,所以加起为五个字节,这样就实现了类的机制。
  
   下面再来分析一下,类的成员函数调用另一成员函数的情况:
  
   27:  void CTest::a(int one,int two)

 28:  {
   00401230  push    ebp
   00401231  mov     ebp,esp
   00401233  sub     esp,44h
   00401236  push    ebx
   00401237  push    esi
   00401238  push    edi
   00401239  push    ecx
   0040123A  lea     edi,[ebp-44h]
   0040123D  mov     ecx,11h
   00401242  mov     eax,0CCCCCCCCh
   00401247  rep stos  dword ptr [edi]
   00401249  pop     ecx
   0040124A  mov     dword ptr [ebp-4],ecx
   29:    printf("call b");
   0040124D  push    offset string "call b" (00422038)
   00401252  call    printf (00401830)
   00401257  add     esp,4
   30:    b();
   0040125A  mov     ecx,dword ptr [ebp-4] //不要想这里的[ebp-4]肯定是this指针,
   0040125D  call    @ILT+15(CTest::b) (00401014) // 又是@ILT静态表格
   31:  }
   00401262  pop     edi
   00401263  pop     esi
   00401264  pop     ebx
   00401265  add     esp,44h
   00401268  cmp     ebp,esp
   0040126A  call    __chkesp (00401670)
   0040126F  mov     esp,ebp
   00401271  pop     ebp
   00401272  ret     8   //由于是STDCALLR所以栈是由程序自己来平衡的

[返回]

编程语言 web开发 数据库 网络技术 操作系统 服务器 网页设计 图形设计 办公软件 常用软件 学电脑

Copyright© www.bianceng.cn Powered by 编程入门网 All Rights Reserved.
关于本站 | 版权声明 | 联系我们 | 友情链接 |
编程入门网 版权所有