从汇编角度看继承和虚函数
#include "stdafx.h"
#include <stdio.h>
class Base
{
public:
virtual int basevt()
{
return 1;
}
};
class Inherit:public Base
{
public:
int basevt()
{
return 2;
};
};
int main(int argc, char* argv[])
{
Inherit inherit;
printf("%d\n", inherit.basevt());
return 0;
}
反汇编后:
.text:00401030 push ebp
.text:00401031 mov ebp, esp
.text:00401033 sub esp, 44h
.text:00401036 push ebx
.text:00401037 push esi
.text:00401038 push edi
.text:00401039 lea edi, [ebp+var_44]
.text:0040103C mov ecx, 11h
.text:00401041 mov eax, 0CCCCCCCCh
.text:00401046 rep stosd
.text:00401048 lea ecx, [ebp+var_4]
.text:0040104B call j_Inherit__Inherit ;调用子类的构造函数
.text:00401050 lea ecx, [ebp+var_4] ;将子类this指针作隐含参数传入
.text:00401053 call j_Inherit__basevt ;调用子类的basevt虚函数;
.text:00401058 push eax
.text:00401059 push offset aD ; "%d\n"
.text:0040105E call printf
.text:00401063 add esp, 8
.text:00401066 xor eax, eax
.text:00401068 pop edi
.text:00401069 pop esi
.text:0040106A pop ebx
.text:0040106B add esp, 44h
.text:0040106E cmp ebp, esp
.text:00401070 call __chkesp
.text:00401075 mov esp, ebp
.text:00401077 pop ebp
.text:00401078 retn
----------------------------------------------------------------------------------------
子类构造函数中:
.text:004010C0 push ebp
.text:004010C1 mov ebp, esp
.text:004010C3 sub esp, 44h
.text:004010C6 push ebx
.text:004010C7 push esi
.text:004010C8 push edi
.text:004010C9 push ecx
.text:004010CA lea edi, [ebp+var_44]
.text:004010CD mov ecx, 11h
.text:004010D2 mov eax, 0CCCCCCCCh
.text:004010D7 rep stosd
.text:004010D9 pop ecx
.text:004010DA mov [ebp+var_4], ecx
.text:004010DD mov ecx, [ebp+var_4]
.text:004010E0 call j_Base__Base ;调用父类构造函数
.text:004010E5 mov eax, [ebp+var_4] ;子类this指针
.text:004010E8 mov dword ptr [eax], offset ??_7Inherit@@6B@ ; const Inherit::`vftable' ;覆盖父类虚函数表指针
.text:004010EE mov eax, [ebp+var_4] ;返回this指针
.text:004010F1 pop edi
.text:004010F2 pop esi
.text:004010F3 pop ebx
.text:004010F4 add esp, 44h
.text:004010F7 cmp ebp, esp
.text:004010F9 call __chkesp
.text:004010FE mov esp, ebp
.text:00401100 pop ebp
.text:00401101 retn
-------------------------------------------------------------------------------------------------------------------
父类构造函数:
.text:0040D7A0 push ebp
.text:0040D7A1 mov ebp, esp
.text:0040D7A3 sub esp, 44h
.text:0040D7A6 push ebx
.text:0040D7A7 push esi
.text:0040D7A8 push edi
.text:0040D7A9 push ecx
.text:0040D7AA lea edi, [ebp+var_44]
.text:0040D7AD mov ecx, 11h
.text:0040D7B2 mov eax, 0CCCCCCCCh
.text:0040D7B7 rep stosd
.text:0040D7B9 pop ecx
.text:0040D7BA mov [ebp+var_4], ecx
.text:0040D7BD mov eax, [ebp+var_4] ;子类this指针.
.text:0040D7C0 mov dword ptr [eax], offset ??_7Base@@6B@ ; const Base::`vftable' 虚函数表指针写入this指针.
.text:0040D7C6 mov eax, [ebp+var_4] ;返回this指针
.text:0040D7C9 pop edi
.text:0040D7CA pop esi
.text:0040D7CB pop ebx
.text:0040D7CC mov esp, ebp
.text:0040D7CE pop ebp
.text:0040D7CF retn
------------------------------------------------------------------------------------------------------
basevt函数:
.text:00401090 push ebp
.text:00401091 mov ebp, esp
.text:00401093 sub esp, 44h
.text:00401096 push ebx
.text:00401097 push esi
.text:00401098 push edi
.text:00401099 push ecx
.text:0040109A lea edi, [ebp+var_44]
.text:0040109D mov ecx, 11h
.text:004010A2 mov eax, 0CCCCCCCCh
.text:004010A7 rep stosd
.text:004010A9 pop ecx
.text:004010AA mov [ebp+var_4], ecx
.text:004010AD mov eax, 2
.text:004010B2 pop edi
.text:004010B3 pop esi
.text:004010B4 pop ebx
.text:004010B5 mov esp, ebp
.text:004010B7 pop ebp
.text:004010B8 retn
综上:
子类继承父类,首先是先调用子类的构造函数分配内存空间,然后调用父类构造函数,将父类的虚函数表指针写入this指针.
之后是子类覆盖父类的虚函数表指针,导致,子类调用父类相同的函数时,将是子类的函数.