源自一道面試題,覺得很有意思
class CBase
{
public:
virtual void PrintData(int nData = 111);
};
void CBase::PrintData(int nData /* = 111 */)
{
printf("CBase::PrintData, nData = %d\n", nData);
}
class CDerived : public CBase
{
public:
void PrintData(int nData = 222);
};
void CDerived::PrintData(int nData /* = 111 */)
{
printf("CDerived::PrintData, nData = %d\n", nData);
}
在main()中做如下調用: CDerived oCDerived;
CBase* pCBase = (CBase*)&oCDerived;
pCBase->PrintData();
(*pCBase).PrintData();
oCDerived.PrintData();
大家先猜猜輸出結果是什麼?是不是更奇怪,我們看看反彙編的代碼:
14、oCDerived.PrintData();
push 0DEh
lea ecx,[ebp-4]
call @ILT+25(CDerived::PrintData) (0040101e) ;直接調用CDerived::PrintData(),無虛表取址過程
15、((CBase)oCDerived).PrintData();
mov esi,esp
push 6Fh ;壓入CBase::PrintData()形參
lea ecx,[ebp-4]
push ecx ;壓入oCDerived的this指針
lea ecx,[ebp-10h]
call @ILT+10(CBase::CBase) (0040100f) ;調用CBase拷貝構造函數新創建了一個CBase對象
mov dword ptr [ebp-14h],eax
mov edx,dword ptr [ebp-14h]
mov eax,dword ptr [edx] ;取新CBase對象的虛表
mov ecx,dword ptr [ebp-14h]
call dword ptr [eax] ;調用新CBase對象的虛表的第一個函數
15.1、CBase::CBase拷貝構造函數;
mov dword ptr [ebp-4],ecx ;取this指針
mov eax,dword ptr [ebp-4]
mov dword ptr [eax],offset CBase::`vftable' (00425024) ;虛表地址賦值,直接用的CBase虛表,而沒有用CDerived的虛表
mov eax,dword ptr [ebp-4] ;將this指針給eax返回
16、pCDerived->PrintData();
mov esi,esp
push 0DEh
mov ecx,dword ptr [ebp-8] ;取pCDerived
mov edx,dword ptr [ecx] ;取虛表
mov ecx,dword ptr [ebp-8] ;放入this指針
call dword ptr [edx] ;調用虛表的第一個函數,即PrintData()