多态性(polymorphisn)是允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。简单的说,就是一句话:允许将子类类型的指针赋值给父类类型的指针。多态包括静态多态就是重载和动态多态覆盖。这里主要讲动态多态。
C++多态性是通过虚函数来实现的,虚函数允许子类重新定义成员函数,而子类重新定义父类的做法称为覆盖(override),或者称为重写。当子类重新定义了父类的虚函数后,父类指针根据赋给它的不同的子类指针,动态(记住:是动态!)的调用属于子类的该函数,这样的函数调用在编译期间是无法确定的(调用的子类的虚函数的地址无法给出)。因此,这样的函数地址是在运行期绑定的(晚邦定)。多态与非多态的实质区别就是函数地址是早绑定还是晚绑定。如果函数的调用,在编译器编译期间就可以确定函数的调用地址,并生产代码,是静态的,就是说地址是早绑定的。而如果函数调用的地址不能在编译器期间确定,需要在运行时才确定,这就属于晚绑定。
那么,多态的作用是什么呢?我们知道,封装可以隐藏实现细节,使得代码模块化;继承可以扩展已存在的代码模块(类);它们的目的都是为了——代码重用。而多态则是为了实现另一个目的——接口重用!多态的作用,就是为了类在继承和派生的时候,保证使用“家谱”中任一类的实例的某一属性时的正确调用。
多态在面向对象编程的时候是怎样实现的呢?最常见的用法就是声明基类的指针,利用该指针指向任意一个子类对象,调用相应的虚函数,可以根据指向的子类的不同而实现不同的方法。如果没有使用虚函数的话,即没有利用C++多态性,则利用基类指针调用相应的函数的时候,将总被限制在基类函数本身,而无法调用到子类中被重写过的函数。因为没有多态性,函数调用的地址将是一定的,而固定的地址将始终调用到同一个函数,这就无法实现一个接口,多种方法的目的了。
#include "iostream"
using namespace std;
class A
{
public:
void foo()
{
cout<<"a"<<endl;
}
virtual void fun()
{
cout<<"b"<<endl;
}
};
class B : public A
{
void foo()
{
cout<<"c"<<endl;
}
void fun()
{
cout<<"d"<<endl;
}
};
class C : public A
{
void fun()
{
cout<<"f"<<endl;
}
};
int main()
{
A obj1;//定义基类的对象
B obj2;//定义子类的对象
C obj3;
cout<<"定义基类的指针指向基类的对象,调用基类中的成员函数"<<endl;
A *p=&obj1;//定义基类的指针指向基类的对象
p->foo();
p->fun();
cout<<"基类的指针指向子类B的对象,虚函数调用子类中重写的函数"<<endl;
p=&obj2;//基类的指针指向子类B的对象,体现多态
p->foo();
p->fun();
cout<<"基类的指针指向子类C的对象,虚函数调用子类中重写的函数"<<endl;
p=&obj3;//基类的指针指向子类C的对象,体现多态
p->foo();
p->fun();
return 0;
}