(1) C++ 类的构造都会做哪些事?

struct Point
{
    int x ;
    int y ;
};
class CBase
{
public:
    CBase(void);
    ~CBase(void);

public:
    Point point ;

public:
    virtual void Draw();
    virtual void Paint();
    void         PulicSet() ;
private:
    int nFinsh ;
};
//构造函数
CBase::CBase(void) { nFinsh = 65535 ; point.x = 55 ; point.y = 44 ; }

从上面的这2段代码开始说起,看构造函数,我们只能看到他初始化了nFind,point 这2个成员对象,那么 构造函数真的只做的这些操作么?

从汇编来看一下它到底还做了什么

01361560 > 55               PUSH EBP
01361561   8BEC             MOV EBP,ESP
01361563   81EC CC000000    SUB ESP,0CC
01361569   53               PUSH EBX
0136156A   56               PUSH ESI
0136156B   57               PUSH EDI
0136156C   51               PUSH ECX
0136156D   8DBD 34FFFFFF    LEA EDI,DWORD PTR SS:[EBP-CC]
01361573   B9 33000000      MOV ECX,33
01361578   B8 CCCCCCCC      MOV EAX,CCCCCCCC
0136157D   F3:AB            REP STOS DWORD PTR ES:[EDI]
0136157F   59               POP ECX                                         ;ecx 为类对象的地址
01361580   894D F8          MOV DWORD PTR SS:[EBP-8],ECX
01361583   8B45 F8          MOV EAX,DWORD PTR SS:[EBP-8]
01361586   C700 04783601    MOV DWORD PTR DS:[EAX],OFFSET CBase@@6B@@std@@2W4_Openmode@12@BationDetails>@@0IB@@QAEXH_N@Zentry_basee   ; 获取到指向类的虚函数表
0136158C   8B45 F8          MOV EAX,DWORD PTR SS:[EBP-8]
0136158F   C740 0C FFFF0000 MOV DWORD PTR DS:[EAX+C],0FFFF                           ;初始化nFinsh
01361596   8B45 F8          MOV EAX,DWORD PTR SS:[EBP-8]
01361599   C740 04 37000000 MOV DWORD PTR DS:[EAX+4],37                             ;初始化point.x
013615A0   8B45 F8          MOV EAX,DWORD PTR SS:[EBP-8]
013615A3   C740 08 2C000000 MOV DWORD PTR DS:[EAX+8],2C                             ;初始化point.y                                              
013615AA   8B45 F8          MOV EAX,DWORD PTR SS:[EBP-8]
013615AD   5F               POP EDI
013615AE   5E               POP ESI
013615AF   5B               POP EBX
013615B0   8BE5             MOV ESP,EBP
013615B2   5D               POP EBP

 我们看到了,在构造函数中 还把vptr 也就是指向虚函数表的地址放到了类对象的地址内,我们看下类对象的内存布局

0018F9C0  01367804  ;指向虚函数表
0018F9C4  00000037  ;point.x
0018F9C8  0000002C  ;point.y
0018F9CC  0000FFFF  ;nFinsh 

接着继续来看一下vptr 内是什么样子的

01367804 >01361032  ;这里就是类所定义的虚函数 这个是Draw()
01367808  0136129E  ; Paint() 

我们可以以vptr[n]的形式来获取到类成员的虚函数,接下来继续跟进去,看看是不是我们想的那样

01361032   E9 D9050000      JMP 虚函数底.CBase::Drawtageif_errorement

01361610 > 55               PUSH EBP
01361611   8BEC             MOV EBP,ESP
01361613   81EC CC000000    SUB ESP,0CC
01361619   53               PUSH EBX
0136161A   56               PUSH ESI
0136161B   57               PUSH EDI
0136161C   51               PUSH ECX
0136161D   8DBD 34FFFFFF    LEA EDI,DWORD PTR SS:[EBP-CC]
01361623   B9 33000000      MOV ECX,33
01361628   B8 CCCCCCCC      MOV EAX,CCCCCCCC
0136162D   F3:AB            REP STOS DWORD PTR ES:[EDI]
0136162F   59               POP ECX
01361630   894D F8          MOV DWORD PTR SS:[EBP-8],ECX
01361633   8BF4             MOV ESI,ESP
01361635   A1 10B33601      MOV EAX,DWORD PTR DS:[<&MSVCP90D.?endl@std@@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@1@AAV21@@Z>]
0136163A   50               PUSH EAX
0136163B   68 0C783601      PUSH OFFSET 虚函数底.??_C@_09HEPBPNEM@Base?5Draw?$AA@ate@12@Bpe?5causing?5los@?$AAc?$AAt?$AAo?$AAo?$AA...                       ; ASCII "Base Draw"
01361640   8B0D 0CB33601    MOV ECX,DWORD PTR DS:[<&MSVCP90D.?cout@std@@3V?$basic_ostream@DU?$char_traits@D@std@@@1@A>]                                 ; MSVCP90D.?cout@std@@3V?$basic_ostream@DU?$char_traits@D@std@@@1@A
01361646   51               PUSH ECX
01361647   E8 30FBFFFF      CALL 虚函数底.0136117C
0136164C   83C4 08          ADD ESP,8
0136164F   8BC8             MOV ECX,EAX
01361651   FF15 08B33601    CALL DWORD PTR DS:[<&MSVCP90D.??6?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV01@P6AAAV01@AAV01@...                   ; MSVCP90D.??6?$basic_ostream@_WU?$char_traits@_W@std@@@std@@QAEAAV01@P6AAAV01@AAV01@@Z@Z
01361657   3BF4             CMP ESI,ESP
01361659   E8 73FBFFFF      CALL 虚函数底.013611D1
0136165E   5F               POP EDI
0136165F   5E               POP ESI
01361660   5B               POP EBX
01361661   81C4 CC000000    ADD ESP,0CC
01361667   3BEC             CMP EBP,ESP
01361669   E8 63FBFFFF      CALL 虚函数底.013611D1
0136166E   8BE5             MOV ESP,EBP
01361670   5D               POP EBP
01361671   C3               RETN

我们的猜想是对的 继续来看 下面一个虚函数地址是不是Paint

0136129E   E9 ED030000      JMP 虚函数底.CBase::Paintageif_errorement

 Bingo,我们猜想是正确的,接下来的文章我们会继续以汇编的角度 来看C++.并且我们会以汇编的方式访问一下虚函数

原文地址:https://www.cnblogs.com/dependence/p/3060046.html