虚函数的解析

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

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

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

// 虚函数.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、付费专栏及课程。

余额充值