中超

C++类机制的实现细节_a

2020-01-17 01:17:01来源:励志吧0次阅读

为了搞清楚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:myownestest.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] file://这是用来保存aTest的this指针,因为是局部变量所以是保存在[ebp-10h]中

00401080  call    @ILT+30(CTest::CTest) (00401023) file://调用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] file://把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] file://同样是this指针

004010A9  call    @ILT+25(CTest::~CTest) (0040101e) file://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] file://不要想这里的[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   file://由于是STDCALLR所以栈是由程序自己来平衡的

舒尔佳减肥药效果好吗
宝宝脾虚怎么办
舒筋活络外用抹药
糖尿病胃轻瘫消化不好的治疗
分享到: