• (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++.并且我们会以汇编的方式访问一下虚函数

  • 相关阅读:
    模拟实现ajax加载框
    京东晒单的js实现
    微信分享js代码(转载)
    css模拟实现selec下拉框
    网页端实现输入卡号四字隔开
    返回顶部的动态显示与隐藏
    js等比例缩放图片(转载)
    css模拟实现checkbox
    quartz的使用 Mr
    Spring声明式事务配置管理方法 Mr
  • 原文地址:https://www.cnblogs.com/dependence/p/3060046.html
Copyright © 2020-2023  润新知