虚函数的解析

      概念上,虚函数是在程序运行时刻才定义的函数,其实其含义是:虚函数是在运行时刻才知道要调用的是子类的方法,还是父类的方法,对于一个含有虚函数的类而言,他的虚

函数的定义在一个地方,还有一个叫做虚函数表的数据结构被存储下来,这个虚函数表,这个虚函数表中存放了每个虚函数的首地址,当我们调用一个虚函数时,他会首先寻找虚

函数表所在,然后根据偏移量获得该虚函数的地址,进而将该虚函数地址中的内容,放进寄存器当中,即真正的函数代码放进寄存器当中,开始函数的调用

// 虚函数.cpp : 定义控制台应用程序的入口点。
#include "stdafx.h"
#include"iostream"
using namespace std;
class base
{	
public:
	
	virtual void demo_1()
	{
		cout<<"demo_1\n";
	}
	virtual void demo_2()
	{
		cout<<"demo_2\n";
	}
	virtual void demo_3()
	{
		cout<<"demo_3\n";
	}
};
class Imp: public base
{
public:
	
	void demo_1()
	{
		cout<<"real demo_1\n";
	}
	void demo_2()
	{
		cout<<"real demo_2\n";
	}
	void demo_3()
	{
		cout<<"real demo_3\n";
	}
};
int _tmain(int argc, _TCHAR* argv[])
{
	
	base *p=new base();
	p->demo_1();
	p->demo_2();
	p->demo_3();
	p=new Imp();
	p->demo_1();
	p->demo_2();
	p->demo_3();
	return 0;
}	

其反汇编后得到的代码是:

.text:00401000 ; ===========================================================================
.text:00401000
.text:00401000 ; Segment type: Pure code
.text:00401000 ; Segment permissions: Read/Execute
.text:00401000 _text           segment para public 'CODE' use32
.text:00401000                 assume cs:_text
.text:00401000                 ;org 401000h
.text:00401000                 assume es:nothing, ss:nothing, ds:_data, fs:nothing, gs:nothing
.text:00401000
.text:00401000 ; =============== S U B R O U T I N E =======================================
.text:00401000
.text:00401000
.text:00401000 ; void __thiscall base__demo_1(base *this)
.text:00401000 public: virtual void __thiscall base::demo_1(void) proc near
.text:00401000                                         ; DATA XREF: .rdata:const base::`vftable'o
.text:00401000 this = ecx
.text:00401000                 mov     eax, ds:std::basic_ostream<char,std::char_traits
  
  
   
   > std::cout
.text:00401005                 push    offset _Val     ; "demo_1\n"
.text:0040100A                 push    eax             ; _Ostr
.text:0040100B                 call    std::operator<<<std::char_traits
   
   
    
    >(std::basic_ostream<char,std::char_traits
    
    
     
     > &,char const *)
.text:00401010                 add     esp, 8
.text:00401013                 retn
.text:00401013 public: virtual void __thiscall base::demo_1(void) endp;以上是基类base的demo_1方法的定义,函数体的所在
.text:00401013
.text:00401013 ; ---------------------------------------------------------------------------
.text:00401014                 align 10h
.text:00401020
.text:00401020 ; =============== S U B R O U T I N E =======================================
.text:00401020
.text:00401020
.text:00401020 ; void __thiscall base__demo_2(base *this)
.text:00401020 public: virtual void __thiscall base::demo_2(void) proc near
.text:00401020                                         ; DATA XREF: .rdata:0040216Co
.text:00401020 this = ecx
.text:00401020                 mov     eax, ds:std::basic_ostream<char,std::char_traits
     
     
      
      > std::cout
.text:00401025                 push    offset aDemo_2  ; "demo_2\n"
.text:0040102A                 push    eax             ; _Ostr
.text:0040102B                 call    std::operator<<<std::char_traits
      
      
        >(std::basic_ostream<char,std::char_traits 
       
         > &,char const *) .text:00401030 add esp, 8 .text:00401033 retn .text:00401033 public: virtual void __thiscall base::demo_2(void) endp;以上是base的demo_2的定义,也就是函数体的所在 .text:00401033 .text:00401033 ; --------------------------------------------------------------------------- .text:00401034 align 10h .text:00401040 .text:00401040 ; =============== S U B R O U T I N E ======================================= .text:00401040 .text:00401040 .text:00401040 ; void __thiscall base__demo_3(base *this) .text:00401040 public: virtual void __thiscall base::demo_3(void) proc near .text:00401040 ; DATA XREF: .rdata:00402170o .text:00401040 this = ecx .text:00401040 mov eax, ds:std::basic_ostream<char,std::char_traits 
        
          > std::cout .text:00401045 push offset aDemo_3 ; "demo_3\n" .text:0040104A push eax ; _Ostr .text:0040104B call std::operator<<<std::char_traits 
         
           >(std::basic_ostream<char,std::char_traits 
          
            > &,char const *) .text:00401050 add esp, 8 .text:00401053 retn .text:00401053 public: virtual void __thiscall base::demo_3(void) endp;以上是base的demo_3的定义,也就是函数体的所在 .text:00401053 .text:00401053 ; --------------------------------------------------------------------------- .text:00401054 align 10h .text:00401060 .text:00401060 ; =============== S U B R O U T I N E ======================================= .text:00401060 .text:00401060 .text:00401060 ; void __thiscall Imp__demo_1(Imp *this) .text:00401060 public: virtual void __thiscall Imp::demo_1(void) proc near .text:00401060 ; DATA XREF: .rdata:const Imp::`vftable'o .text:00401060 this = ecx .text:00401060 mov eax, ds:std::basic_ostream<char,std::char_traits 
           
             > std::cout .text:00401065 push offset aRealDemo_1 ; "real demo_1\n" .text:0040106A push eax ; _Ostr .text:0040106B call std::operator<<<std::char_traits 
            
              >(std::basic_ostream<char,std::char_traits 
             
               > &,char const *) .text:00401070 add esp, 8 .text:00401073 retn .text:00401073 public: virtual void __thiscall Imp::demo_1(void) endp;以上是子类Imp的demo_1的定义,也就是函数体的所在 .text:00401073 .text:00401073 ; --------------------------------------------------------------------------- .text:00401074 align 10h .text:00401080 .text:00401080 ; =============== S U B R O U T I N E ======================================= .text:00401080 .text:00401080 .text:00401080 ; void __thiscall Imp__demo_2(Imp *this) .text:00401080 public: virtual void __thiscall Imp::demo_2(void) proc near .text:00401080 ; DATA XREF: .rdata:0040217Co .text:00401080 this = ecx .text:00401080 mov eax, ds:std::basic_ostream<char,std::char_traits 
              
                > std::cout .text:00401085 push offset aRealDemo_2 ; "real demo_2\n" .text:0040108A push eax ; _Ostr .text:0040108B call std::operator<<<std::char_traits 
               
                 >(std::basic_ostream<char,std::char_traits 
                
                  > &,char const *) .text:00401090 add esp, 8 .text:00401093 retn .text:00401093 public: virtual void __thiscall Imp::demo_2(void) endp;以上是Imp的demo_2的定义,也就是函数体所在 .text:00401093 .text:00401093 ; --------------------------------------------------------------------------- .text:00401094 align 10h .text:004010A0 .text:004010A0 ; =============== S U B R O U T I N E ======================================= .text:004010A0 .text:004010A0 .text:004010A0 ; void __thiscall Imp__demo_3(Imp *this) .text:004010A0 public: virtual void __thiscall Imp::demo_3(void) proc near .text:004010A0 ; DATA XREF: .rdata:00402180o .text:004010A0 this = ecx .text:004010A0 mov eax, ds:std::basic_ostream<char,std::char_traits 
                 
                   > std::cout .text:004010A5 push offset aRealDemo_3 ; "real demo_3\n" .text:004010AA push eax ; _Ostr .text:004010AB call std::operator<<<std::char_traits 
                  
                    >(std::basic_ostream<char,std::char_traits 
                   
                     > &,char const *) .text:004010B0 add esp, 8 .text:004010B3 retn .text:004010B3 public: virtual void __thiscall Imp::demo_3(void) endp;以上是Imp的demo_3的定义,也就是函数体的所在 .text:004010B3 .text:004010B3 ; --------------------------------------------------------------------------- .text:004010B4 align 10h .text:004010C0 .text:004010C0 ; =============== S U B R O U T I N E ======================================= .text:004010C0 .text:004010C0 .text:004010C0 ; int __cdecl wmain(int argc, wchar_t **argv) .text:004010C0 _wmain proc near ; CODE XREF: __tmainCRTStartup+11Dp .text:004010C0 .text:004010C0 argc = dword ptr 8 .text:004010C0 argv = dword ptr 0Ch .text:004010C0 .text:004010C0 push esi .text:004010C1 push edi .text:004010C2 mov edi, ds:operator new(uint) .text:004010C8 push 4 .text:004010CA call edi ; operator new(uint);分配内存4个字节的内存 .text:004010CC add esp, 4;分配完之后清空栈 .text:004010CF test eax, eax;检查空间分配是否成功 .text:004010D1 jz short loc_4010DD .text:004010D3 mov dword ptr [eax], offset const base::`vftable';将虚函数表的首地址放在eax指向的内存区域当中 .text:004010D9 mov esi, eax .text:004010DB jmp short loc_4010DF .text:004010DD ; --------------------------------------------------------------------------- .text:004010DD .text:004010DD loc_4010DD: ; CODE XREF: _wmain+11j .text:004010DD xor esi, esi;之后在内存分配失败时,才会进行此操作 .text:004010DF .text:004010DF loc_4010DF: ; CODE XREF: _wmain+1Bj .text:004010DF mov eax, [esi];将虚函数表的首地址放在eax当中 .text:004010E1 mov edx, [eax];将虚函数表的第一个函数的起始地址放在edx当中 .text:004010E3 mov ecx, esi;将虚函数表的首地址保存下来 .text:004010E5 call edx; .text:004010E7 mov eax, [esi] .text:004010E9 mov edx, [eax+4];注意这是将虚函数表中的第二个函数起始地址放在edx中,然后进行调用 .text:004010EC mov ecx, esi .text:004010EE call edx .text:004010F0 mov eax, [esi] .text:004010F2 mov edx, [eax+8] .text:004010F5 mov ecx, esi .text:004010F7 call edx .text:004010F9 push 4 .text:004010FB call edi ; operator new(uint) .text:004010FD add esp, 4; .text:00401100 test eax, eax .text:00401102 jz short loc_40110E .text:00401104 mov dword ptr [eax], offset const Imp::`vftable' .text:0040110A mov esi, eax .text:0040110C jmp short loc_401110 .text:0040110E ; --------------------------------------------------------------------------- .text:0040110E .text:0040110E loc_40110E: ; CODE XREF: _wmain+42j .text:0040110E xor esi, esi .text:00401110 .text:00401110 loc_401110: ; CODE XREF: _wmain+4Cj .text:00401110 mov eax, [esi] .text:00401112 mov edx, [eax] .text:00401114 mov ecx, esi .text:00401116 call edx .text:00401118 mov eax, [esi] .text:0040111A mov edx, [eax+4] .text:0040111D mov ecx, esi .text:0040111F call edx .text:00401121 mov eax, [esi] .text:00401123 mov edx, [eax+8] .text:00401126 mov ecx, esi .text:00401128 call edx .text:0040112A pop edi .text:0040112B xor eax, eax .text:0040112D pop esi .text:0040112E retn .text:0040112E _wmain endp 
                    
                   
                  
                 
                
               
              
             
            
           
          
         
        
      
     
     
    
    
   
   
  
  
以下的是虚函数表:

.rdata:00402168 const base::`vftable' dd offset base::demo_1(void) ; DATA XREF: _wmain+13o
.rdata:0040216C                 dd offset base::demo_2(void)
.rdata:00402170                 dd offset base::demo_3(void)
.rdata:00402174                 dd offset const Imp::`RTTI Complete Object Locator'
.rdata:00402178 const Imp::`vftable' dd offset Imp::demo_1(void) ; DATA XREF: _wmain+44o
.rdata:0040217C                 dd offset Imp::demo_2(void)
.rdata:00402180                 dd offset Imp::demo_3(void)
.rdata:00402184                 align 8
.rdata:00402188 __load_config_used db  48h ; H

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

世纪殇

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值