多态性
概念:向不同的对象发送同一个消息,不同的对象在接收时会产生不同的行为(即方法)。
作用:可以实现一个接口,多种方法
应用:多态性分为静态多态性和动态多态性,静态多态性即编译时的多态性,通过函数重载实现;动态多态性是运行时才确定操作所作用的对象,动态多态性通过虚函数(virtual function)实现;
例子:
建立一个Point(点)类,包含数据成员x,y(坐标点)。以它为基类,派生出一个Circle(圆)类,增加数据成员r(半径),再以Circle类为直接基类,派生出一个Cylinder(圆柱体)类,再增加数据成员h(高)。要求编写程序,重载运算符“<<”和“>>”,使之能用于输出以上类对象。
对于一个比较大的程序,应当分成若干步骤进行。先声明基类,再声明派生类,逐级进行,分步调试。
//首先实现基类point
#include <iostream>
using namespace std;
class point
{
public:
point(float x=0, float y=0);//构造函数,初始化坐标(0,0)
void setPoint(float, float);
float getx() const {return x;}
float gety() const {return y;}
friend ostream & operator<<(ostream &, const point &);
protected:
float x, y;
};
void point::setPoint(float a, float b)
{
x = a;
y = b;
}
point::point(float a, float b)
{
x = a;
y = b;
}
ostream & operator<<(ostream & output, const point & p)
{
output << "[" << p.x << "," << p.y << "]" << endl;
return output;
}
int main()
{
point p(3.5, 6.4);
cout<<"x="<<p.getx()<< " y=" << p.gety()<<endl;
p.setPoint(1.1,3.2);
cout << "pnew = " << p << endl;
}
//输出结果
x=3.5 y=6.4
pnew = [1.1,3.2]
//声明派生类circle
//派生类
class circle:public point
{
public:
circle(float x=0, float y=0, float r=0);//构造函数
void setRadius(float);//设置半径值
float getRadius() const;
float area() const;//计算圆面积
friend ostream &operator<<(ostream &, const circle &);//重载运算符<<,输入参数为一个输出流引用及circle对象引用
private:
float radius;
};
//定义构造函数,对圆心坐标和半径初始化
circle::circle(float a, float b, float r):point(a,b),radius(r)
{
}
void circle::setRadius(float r)
{
radius = r;
}
float circle::getRadius() const
{
return radius;
}
ostream & operator<<(ostream & output, const circle & c)
{
output << "Center = [" << c.x << "," << c.y<< "], r = " << c.radius << ", area = " << c.area() << endl;
return output;
}
float circle::area() const
{
float radius = getRadius();
return 3.14159*radius*radius;
}
将int main(){}更改为:
int main()
{
point p(3.5, 6.4); //p
cout<<"x="<<p.getx()<< " y=" << p.gety()<<endl;
p.setPoint(1.1,3.2);
cout << "pnew = " << p << endl;
circle c(2.5, 6.4, 4.3);//建立circle对象,并给出圆心和半径
cout << "origina circle:" << c.getx() << ", y = " << c.gety() << ", r = " << c.getRadius() << ", area = " << c.area() << endl;
c.setRadius(7.0);
c.setPoint(2.0, 2.0);
cout << "new circle:" << c;
point &pRef = c;
cout << "pRef:" << pRef;
return 0;
}
//运行结果
x=3.5 y=6.4
pnew = [1.1,3.2]
origina circle:2.5, y = 6.4, r = 4.3, area = 58.088
new circle:Center = [2,2], r = 7, area = 153.938
pRef:[2,2]
接下来再从派生类circle派生出cylinder类
//cylinder类
//增加高度属性
//声明circle的派生类cylinder
class cylinder:public circle
{
public:
cylinder(float x=0, float y=0, float r=0, float h=0);//构造函数
void setHeight(float);//设置圆柱高
float getHeight() const;//获取圆柱高度
float volume() const;//计算圆柱体积
friend ostream & operator<<(ostream &, const cylinder &);
private:
float height;//圆柱高度
};
cylinder::cylinder(float a, float b, float r, float h)
:circle(a, b, r),height(h)
{
}
void cylinder::setHeight(float h)
{
height = h;
}
float cylinder::getHeight() const
{
return height;
}
float cylinder::volume() const
{
float height = getHeight();
float area = circle::area();
return (area*height);
}
//重载运算符 <<
ostream & operator<<(ostream & output, const cylinder & cy)
{
output << "Center = [" << cy.x << cy.y << "]" << ", r = " << cy.getRadius() << ", h = " << cy.height
<< "\narea = " << cy.area() << ", volume = " << cy.volume() << endl;
return output;
}
将int main(){}更改为:
int main()
{
//point test
point p(3.5, 6.4); //p
cout<<"x="<<p.getx()<< " y=" << p.gety()<<endl;
p.setPoint(1.1,3.2);
cout << "p-new = " << p << endl;
//circle test
circle c(2.5, 6.4, 4.3);//建立circle对象,并给出圆心和半径
cout << "origina circle:x = " << c.getx() << ", y = " << c.gety() << ", r = " << c.getRadius() << ", area = " << c.area() << endl;
c.setRadius(7.0);
c.setPoint(2.0, 2.0);
cout << "new circle:" << c;
point &pRef = c;
cout << "pRef:" << pRef;
//cylinder test
cylinder cy(3.2, 7.6, 7.5, 4.3);//建立cylinder对象,并给出圆心,半斤,高度
cout << "original cylinder:x = " << cy.getx() << ", y = " << cy.gety() << ", r = " << cy.getRadius() << ", h = " << cy.getHeight() << endl;
cy.setPoint(1.0, 1.0);
cy.setRadius(3.0);
cy.setHeight(6.5);
cout << "new cylinder:" << cy;
point &pRef1 = cy;
cout << pRef1;//作为点输出
circle &pRef2 = cy;
cout << pRef2;//作为圆输出
return 0;
}
输出:
x=3.5 y=6.4
p-new = [1.1,3.2]
origina circle:x = 2.5, y = 6.4, r = 4.3, area = 58.088
new circle:Center = [2,2], r = 7, area = 153.938
pRef:[2,2]
original cylinder:x = 3.2, y = 7.6, r = 7.5, h = 4.3
new cylinder:Center = [11], r = 3, h = 6.5
area = 28.2743, volume = 183.783
[1,1]
Center = [1,1], r = 3, area = 28.2743
上例的静态多态性是运算符重载引起的。可以看到,在编译时编译系统即可以判定应调用哪个重载运算符函数。稍后将在此基础上讨论动态多态性问题。
动态多态性通过虚函数实现:
虚函数的作用是允许在派生类中重新定义与基类同名的函数,并且可以通过基类指针或引用来访问基类和派生类中的同名函数。