C++中關於動態多態自己的理解仍然太淺了,對於多次在基類和派生類中來回調用的一些情況,仍然會產生動態多態的情況。
求如下程序的輸出結果:
#include<iostream>
#include<string>
using namespace std;
class Base
{
public:
virtual void Send()
{
cout << "\nSend_Base:" << mVal << endl;
}
~Base() {}
void OutPut()
{
Send();
}
int mVal;
};
class Derive :public Base
{
public:
Derive() { mVal = 100; }
virtual void Send()
{
mVal++;
cout << "\nSend_Der: " << mVal << endl;
}
void OutPut()
{
Base::OutPut();
}
};
int main()
{
Derive user;
Base &base = user;
base.Send();
Base *p = &base;
p->OutPut();
user.OutPut();
return 0;
}
1、分析
(1)、Send()
爲虛函數,當通過基類的引用或指針來調用該虛函數時會產生動態多態。所以Base &base=user
爲基類的引用綁定到派生類的對象上,base.Send()
中由於調用的爲虛函數,所以會產生動態多態,此時基類引用綁定的是派生類對象,所以會調用派生類的虛函數。
(2)、第二個輸出對於我來說有很大的迷惑性,由於base
是綁定到派生類對象上的引用,所以base
相當於派生類對象的別名。Base *p=&base
相當於將派生類對象的地址賦給基類指針,p
就成爲指向派生類對象的基類指針,此時若調用虛函數就會產生動態多態的行爲。而迷惑在於p->OutPut()
,在類中OutPut()
爲普通成員函數,而非虛函數。因此就會調用基類的OutPut
函數,但是基類OutPut()
函數中又調用了虛函數Send()
,而此時的調用對象爲指向派生類的基類指針,因此仍然會產生動態多態的行爲,會調用派生類的虛函數Send()
。
(3)、第三個是直接使用派生類對象來調用OutPut()
函數,所以會直接調用派生類的OutPut
成員函數,但是該成員函數又直接調用了基類的OutPut
函數,因此會回到基類的OutPut
函數中去調用虛函數Send
,此時由於調用對象一直是派生類,所以會直接調用派生類所對應的虛函數。在此處是拐了好幾個彎的來回在基類和派生類中進行調用,但是由於是直接通過派生類對象來進行調用的,而不是基類指針或引用來調用,所以在第三個調用中不會產生動態多態。
總結分析:在涉及到虛函數的調用中,有可能會產生動態多態的情況下,首先看是否通過基類的指針或引用來最終調用了虛函數(不管拐了多少彎,最後調用虛函數的時候一定要看,調用的對象是否爲基類指針或引用)。若爲基類指針或引用就會產生多態行爲,否則就只是根據調用函數的對象類型來確定調用的版本。