虚函数中调用虚函数实现多态的原因

        对于前者,通过基类指针或引用调用统一接口(声明为虚函数)实现子类功能的多态情况,我们可以分析是因为此时基类指针中包含的vptr指向的是子类中的vptr,所以调用统一接口时,调用的是vptr所指vtable中对于函数位置的地址,该地址被子类虚函数所替换,故调用的是子类函数。

        然而对于虚函数中调用虚函数,该如何解释多态行为呢?对于第一层的虚函数,我们可以通过以上方式分析,但在虚函数中又调用虚函数,此时的虚函数的函数调用是如何实现呢?请看下面分析:

//----mor.h------
#ifndef MOR_H
#define MOR_H
class A
{
public:
virtual void fun(void);
virtual void gun(void);
};
class B: public A
{
public:
virtual void gun(void);
};
#endif
//---------mor.cpp---------
#include "stdafx.h"
#include "mor.h"
#include <iostream>
using namespace std;
void A::fun(void)
{
cout << "A:fun" << endl;
gun();
}
void A::gun(void)
{
cout << "A::gun" << endl;
}
void B::gun(void)
{
cout << "B::gun" << endl;
}
//----------------main fun--------------------
#include "stdafx.h"
#include "mor.h"

int _tmain(int argc, _TCHAR* argv[])
{
	B b;
	b.fun();
	getchar();
	return 0;
}

输出结果是:

A:fun

B:gun

原因是在虚函数中调用虚函数时,其调用过程是:(请看一下汇编)

B b;
00D321DE  lea         ecx,[b]  
00D321E1  call        B::B (0D3113Bh)  
	b.fun();
00D321E6  lea         ecx,[b]  
00D321E9  call        A::fun (0D31023h)

跟进A::fun后可得:

gun();
00D3157E  mov         eax,dword ptr [this]  // 此处是关键,从这开始又可以以第一种方式分析虚函数调用机制了
00D31581  mov         edx,dword ptr [eax]  
00D31583  mov         esi,esp  
00D31585  mov         ecx,dword ptr [this]  
00D31588  mov         eax,dword ptr [edx+4]  
00D3158B  call        eax  
00D3158D  cmp         esi,esp

由此可知,在虚函数中调用虚函数,会将当前对象的地址放入寄存器,然后根据vptr算得该虚函数的地址,从而实现了多态。

从这里我们可以看到函数的一个调用情况,同时也了解到了虚函数内调用虚函数的多态实现原因。

你可能感兴趣的:(多态实现机制)