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
,此时由于调用对象一直是派生类,所以会直接调用派生类所对应的虚函数。在此处是拐了好几个弯的来回在基类和派生类中进行调用,但是由于是直接通过派生类对象来进行调用的,而不是基类指针或引用来调用,所以在第三个调用中不会产生动态多态。
总结分析:在涉及到虚函数的调用中,有可能会产生动态多态的情况下,首先看是否通过基类的指针或引用来最终调用了虚函数(不管拐了多少弯,最后调用虚函数的时候一定要看,调用的对象是否为基类指针或引用)。若为基类指针或引用就会产生多态行为,否则就只是根据调用函数的对象类型来确定调用的版本。