构造函数中调用虚函数

#include <iostream>

using namespace std;

class Base
{
 public:

  Base(void);
  virtual ~Base();
  virtual void Foo(void);

 private:
  int m_b;
};

Base::Base(void) : m_b(0x123) //为了便于在汇编代码中定位 赋值为 0x123
{
 cout << "Base construction" << endl;
 cout << "call Foo in Base construction" << endl;
 Foo();
}

Base::~Base()
{
 cout << "Base destruction" << endl;
}

void Base::Foo(void)
{
 cout << "Base Foo" << endl;
}

class Derive : public Base
{
 public:
  Derive(void);
  ~Derive();

  virtual void Foo(void);

 private:
  int m_d;
};

Derive::Derive(void) : Base(), m_d(0x456)
{
 cout << "Derive construction" << endl;
}

Derive::~Derive()
{
 cout << "Derive destruction" << endl;
}

void Derive::Foo(void)
{
 cout << "Derive Foo" << endl;
}


int main(int argc, char* argv[])
{
 cout << "create Base instance" << endl;
 Base base;

 cout << endl << "create Derive instance" << endl;
 Derive derive;

 cout << endl << "create Derive instance by new" << endl;
 Base* bptr = new Derive;
 bptr->Foo();

 delete bptr;

 return 0;
}

运行结果:

create Base instance
Base construction
call Foo in Base construction
Base Foo

create Derive instance
Base construction
call Foo in Base construction
Base Foo
Derive construction

create Derive instance by new
Base construction
call Foo in Base construction
Base Foo
Derive construction
Derive Foo
Derive destruction
Base destruction

 

构造函数的汇编代码                              

:00401168 push ebp                     ;Base的构造函数起始位置 
:00401169 mov ebp, esp
:0040116B add esp, FFFFFFDC
:0040116E mov eax, 00402184
:00401173 call 00401C0C
:00401178 mov [ebp-14], 0008
:0040117E mov edx, 004023C0            ;将Base类的虚函数表 vtable地址004023C0 放入edx
:00401183 mov ecx, dword ptr [ebp+08]  ;ecx = this
:00401186 mov dword ptr [ecx], edx     ;将Base类的虚函数表 vtable地址004023C0 放入Base的this指针指向的地址
:00401188 mov eax, dword ptr [ebp+08]
:0040118B mov [eax+04], 00000123       ;初始化成员变量m_b为0x123 
:00401192 push 004020A4
:00401197 mov edx, dword ptr [00405184]
:0040119D push edx
:0040119E call 004011F8
:004011A3 add esp, 00000008
:004011A6 push eax
:004011A7 call 004015A8
:004011AC pop ecx
:004011AD push 004020B6
:004011B2 mov ecx, dword ptr [00405184]
:004011B8 push ecx
:004011B9 call 004011F8
:004011BE add esp, 00000008
:004011C1 push eax
:004011C2 call 004015A8
:004011C7 pop ecx
:004011C8 mov eax, dword ptr [ebp+08]      ;eax = this
:004011CB push eax
:004011CC mov edx, dword ptr [eax]         ;edx = 虚函数表 vtable的地址
:004011CE call [edx+04]                    ;调用Foo
:004011D1 pop ecx
:004011D2 mov ecx, dword ptr [ebp-24]
:004011D5 mov dword ptr fs:[00000000], ecx
:004011DC mov eax, dword ptr [ebp+08]
:004011DF mov esp, ebp
:004011E1 pop ebp
:004011E2 ret

:004017D8 push ebp                        ;Derive的构造函数起始位置   
:004017D9 mov ebp, esp                      
:004017DB add esp, FFFFFFDC                 
:004017DE mov eax, 004022B0                 
:004017E3 call 00401C0C                     
:004017E8 mov [ebp-14], 0008                
:004017EE mov edx, dword ptr [ebp+08]     ;edx = this  
:004017F1 push edx                          
:004017F2 call 00401168                   ;调用Base的构造函数  
:004017F7 pop ecx                           
:004017F8 inc [ebp-08]                      
:004017FB mov ecx, 004023AC               ;将Derive类的虚函数表 vtable的地址004023AC 放入ecx  
:00401800 mov eax, dword ptr [ebp+08]     ;eax = this    
:00401803 mov dword ptr [eax], ecx        ;将Derive类的虚函数表 vtable的地址004023AC 放入Derive的this指针所指向的地址  
:00401805 mov edx, dword ptr [ebp+08]     ;edx = this    
:00401808 mov [edx+08], 00000456          ;初始化成员变量m_d为0x456, [this]是虚函数表地址 
:0040180F push 004020EE                   ;[this+04]是Base的m_b [this+08]是Derive的m_d  
:00401814 mov ecx, dword ptr [00405184]     
:0040181A push ecx                          
:0040181B call 004011F8                     
:00401820 add esp, 00000008                 
:00401823 push eax                          
:00401824 call 004015A8                     
:00401829 pop ecx                           
:0040182A mov eax, dword ptr [ebp-24]       
:0040182D mov dword ptr fs:[00000000], eax  
:00401833 mov eax, dword ptr [ebp+08]       
:00401836 mov esp, ebp                      
:00401838 pop ebp                           
:00401839 ret                               

 

包含虚函数的类的起始地址处保存的是虚函数表的地址,这个地址值是由类的构造函数填写进去的。
在生成派生类Derive的实例时,由Derive的构造函数来调用Base的构造函数先完成基类Base的构建。Base的构造函数中调用虚函数Foo,此时从虚函数表中获取的只能是Base类的虚函数表的地址,因此虚函数Foo绑定的是Base类的Foo,只能执行Base的Foo。

在生成派生类Derive的实例时,Derive的this指针指向的地址其实首先被Base的构造函数填充一次,然后又被Derive的构造函数填充一次。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值