多态性与虚函数
多态性是指具有不同功能的函数可以用同一个函数名。
虚函数是允许在派生类中重新定义与基类同名的函数,并且可以通过基类指针或引用来访问基类和派生类中的同名函数。
(1).在基类用virtual声明成员函数为虚函数。在类外定义虚函数时不必加virtual。
(2).在派生类中重新定义虚函数时,要求函数名、函数类型、函数参数个数和类型全部与基类的虚函数一样。可根据需要重新定函数体。
一个成员函数被声明为虚函数时,其派生类中的同名函数都自动成为虚函数。
(3).定义一个基类对象的指针变量并使他指向其某一派生类的对象。
确定调用具体对象的过程称为关联。
在编译时可确定调用的虚函数属于哪一个类,其过程称为静态关联;在运行时进行关联的称为早期关联。函数重载属于静态关联。
在编译程序时系统就能决定调用的是哪个函数,静态多态又称编译时的多态性,静态多态性是通过函数重载实现的。动态多态性是在程序运行过程中才动态确定操作所针对的对象的。又称运行时的多态性。
例:
#include <iostream>
using namespace std;
//定义基类Point
class Point
{
public:
Point(){ }
virtual ~Point() //Pointl类的析构函数
{
cout<<"1.Point"<<endl;
}
};
//定义派生类Circle
class Circle:public Point
{
public:
Circle(){ }
~Circle() //Circle类的析构函数
{
cout<<"2.Circle"<<endl;
}
};
int main()
{
Point *p = new Circle; //用new开辟Circle类对象的动态存储空间
delete p; //用delete释放动态存储空间
return 0;
}
输出结果为:
2.Circle
1.Point
纯虚函数与抽象类:
纯虚函数:
纯虚函数是在声明虚函数时被初始化为“0”的函数。
Virtual 函数类型 函数名 (参数列表) = 0;
(1).纯虚函数没有函数体。
(2).最后面的“=0”并不表示函数返回值为0,他只是形式上的作用,标志这是纯虚函数。
(3).纯虚函数的作用,在基类中保留一个函数名字,方便派生类根据需要定义。
抽象类:
不用来定义对象,而只作为一种基本类型用作继承的类称为抽象类。
派生类对基类(抽象类)的所有虚函数进行了定义,则这个派生类不是抽象类。如果派生类只定以基类的部分抽象类,则这个派生类仍然为抽象类。
实例:
抽象基类Shape(形状),Point(点),Circle(圆),Cylinder(圆柱体)都是Shape类的直接派生类。
#include <iostream>
using namespace std;
//声明抽象基类Shape
class Shape
{
public:
virtual float area() const //虚函数
{
return 0.0;
}
virtual float volume() const //虚函数
{
return 0.0;
}
virtual void shapeName() const = 0; //纯虚函数
};
//声明Point类
class Point:public Shape
{
public:
Point(float=0,float=0);
void setPoint(float,float);
float getX() const { return x; }
float getY() const { return y; }
virtual void shapeName() const { cout<<"Point:"; }
friend ostream & operator << (ostream & output,const Point &);
protected:
float x,y;
};
//定义Point类成员函数
Point::Point(float a,float b)
{
x = a;
y = b;
}
void Point::setPoint(float a,float b)
{
x = a;
y = b;
}
ostream & operator << (ostream & output,const Point &p )
{
output<<"["<<p.x<<","<<p.y<<"]";
return output;
}
// 声明 Circle类
class Circle:public Point
{
public:
Circle(float x = 0,float y = 0,float r = 0);
void setRadius(float); //设置半径
float getRadius() const;
virtual float area() const;
virtual void shapeName() const { cout<<"Circle"; } //对虚函数进行再定义
friend ostream& operator << (ostream & output,const Circle &);
protected:
float radius;
};
Circle::Circle(float x,float y,float r):Point(x,y),radius(r) {}
void Circle::setRadius(float r)
{
radius = r;
}
float Circle::getRadius() const { return radius; }
float Circle::area() const { return 3.14159 * radius*radius; }
ostream &operator <<(ostream & output,const Circle &c)
{
output<<"["<<c.x<<","<<c.y<<"],r="<<c.radius;
return output;
}
//声明Cyclinder类
class Cylinder : public Circle
{
public:
Cylinder (float x = 0,float y = 0,float r = 0,float h = 0);
void setHeight(float);
virtual float area() const;
virtual float volume() const;
virtual void shapeName() const { cout<<"Cylinder"; } //对虚函数进行再定义
friend ostream & operator << (ostream & ,const Cylinder &);
protected:
float height;
};
//定义Cylinder成员函数
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::area() const
{
return 2*Circle::area()+2*3.14159*radius*height;
}
float Cylinder::volume() const
{
return Circle::area()*height;
}
ostream &operator<<(ostream & output,const Cylinder&cy)
{
output<<"["<<cy.x<<","<<cy.y<<"],r="<<cy.radius<<",h="<<cy.height;
return output;
}
int main()
{
Point point(3.2,4.5); //建立Point对象
Circle circle(2.4,1.2,5.6); //建立Circle类对象
Cylinder cylinder(3.2,6.4,5.2,10.5); //建立Cylinder对象
point.shapeName(); //静态关联
cout<<point<<endl;
circle.shapeName(); //静态关联
cout<<cylinder<<endl<<endl;
Shape *pt; //定义基类指针
pt = &point; //指针指向Point
pt->shapeName(); //动态关联
cout<<"x="<<point.getX()<<"y="<<point.getY()<<"\narea="<<pt->area()<<"\nvolume="<<pt->volume()<<"\n\n";
pt = &circle; //指针指向Circle类对象
pt->shapeName(); //动态关联
cout<<"x="<<circle.getX()<<"y="<<circle.getY()<<"\narea="<<pt->area()<<"\nvolume="<<pt->volume()<<"\n\n";
pt = &cylinder; //指针指向Cylinder类对象
pt->shapeName(); //动态关联
cout<<"x="<<cylinder.getX()<<"y="<<cylinder.getY()<<"\narea="<<pt->area()<<"\nvolume="<<pt->volume()<<"\n\n";
return 0;
}