多态性(polymorphism)是面向对象程序设计的一个重要特征。在面向对象方法中,一般是这样表述多态性的:向不同的对象发送同一个消息,不同的对象在接收时会产生不同的行为。在C++中,多态性表现形式之一是:具有不同功能的函数可以用同一个函数名,这样就可以实现用一个函数名调用不同内容的函数。
从系统实现的角度来看,多态性分两类:静态多态性和动态多态性。 静态多态性是通过函数重载实现的。要求在程序编译时就知道调用函数的全部信息,因此,在程序编译时系统就能决定要调用的是哪个函数。动态多样性的特点是:不在编译时确定调用的是哪个函数,而是在程序运行过程中才动态地确定操作针对的对象。动态多态性是通过虚函数(virtual function)实现的。
本文先来介绍一下静态多态性,下面用一个例子简单介绍一下函数重载和函数覆盖。
(程序会比较长,对于一个比较长的程序,应当分成若干步骤进行分析。)
首先定义一个Point类作为基类:
#ifndef POINT
#define POINT
#include
using namespace std;
class Point
{public:
Point(float x=0.0,float y=0.0);
void setPoint(float,float);
float getX()const{return x;};
float getY()const{return y;};
friend ostream & operator<<(ostream &output,const Point &p)//友元重载运算符<<
{output<<"["<
<<","<
<<"]"<
然后是定义Circle类,属于Point的公有派生类:
#ifndef CIRCLE
#define CIRCLE
#include
#include"Point.h"
using namespace std;
class Circle:public Point
{public:
Circle(float x=0.0,float y=0.0,float r=0.0);
void setRadius(float);
float getRadius()const;
float area()const;
friend ostream & operator<<(ostream &output,const Circle &c)//友元重载运算符<<
{output<<"Center=["<
<<","<
<<"],r="<
<<",area="<
<
然后是定义Cylinder类,属于Circle类的公有派生类:
#ifndef CYLINDER
#define CYLINDER
#include
#include"Circle.h"
#include"Point.h"
using namespace std;
class Cylinder:public Circle
{public:
Cylinder(float x=0.0,float y=0.0,float r=0.0,float h=0.0);
void setHeight(float);
float getHeight() const;
float area() const;
float volume() const;
friend ostream& operator<<(ostream &output,const Cylinder& cy)
{output<<"Center=["<
<<","<
<<"],r="<
<<",h="<
<<"\narea="<
<<",volume="<
<
最后是main函数,测试这三个类:
#include
#include"Point.h"
#include"Circle.h"
#include"Cylinder.h"
using namespace std;
int main()
{
cout<<"测试Point类:"<
测试结果如下图:
下面我们来分析以上三个类:
可以看出,在Point类中,我们声明了一次运算符“<<”重载函数,在Circle类中,我们又声明了一次运算符“<<”重载函数,两次重载的运算符“<<”内容是不一样的,在编译时编译系统会根据输出项的类型确定调用哪一个运算符重载函数,这属于静态多态性。
(一)请注意main函数中的:Point &pRef=c;(例一处)
该处定义了Point类的引用pRef,并用派生类Circle对象c对其初始化。Circle是Point的公用派生类,因此,对象c包括了公用基类部分和公用派生类新增部分,因为引用pRef被定义为Point类,所以,pRdf不能认为是代表了c,它只是代表了c中公用基类的部分。引用pRef得到了c的起始地址,与c中公用基类部分共享了同一段存储单元。所以用“cout<<pRef”输出时,调用的不是Circle中声明的运算符重载函数,而是在Point中声明的运算符重载函数,输出的是“点”的信息,而不是“圆“的信息。
(二)请注意Cylinder类定义中的area函数(例二处)
该处的area函数与Circle类中定义的area函数同名,在main函数调用cyl.area()(例三处)时,调用的是Cylinder类的area函数。这里两个类的area函数并不是重载函数,因为它们不仅函数名相同,而且函数类型和参数个数都相同,这样的两个函数不在同一个类中,而是分别在基类和派生类中,属于同名覆盖。
(三)注意main函数中的:Point &ppRef=cyl;(例四处)和Circle &cRef=cyl;(例五处)
与例一处相同,ppRef为cyl中属于Point类的那部分,cRef为cyl中属于Circle类的那部分。所以输出的分别是“点”和“圆”,而不是“圆柱”。
在本文的程序中,有三个运算符函数时重载(不是同名覆盖),而在编译时,编译系统即可判定应该调用哪个重载运算符函数,这体现了静态多态性。
参考资料:《C++程序设计与分析(第二版)》.谭浩强.清华大学出版社.2011.8.pag392-398