16多态
多态性:在程序多次执行时,某一确定位置的函数调用执行了不同的函数体。
虚函数
虚函数的定义
1.在成员函数(非静态、非构造函数)原型前加上关键字virtual
2.类的虚函数通过继承向下传递,在派生类中既可以直接继承也可以重定义,重定义时函数原型前可以省略virtual,也可以改变访问模式(不提倡),但必须和原来的虚函数具有相同的返回值类型和参数表
虚函数的调用
用对象指针或对象引用对虚函数的调用、成员函数(构造函数和析构函数除外)的函数体中对虚函数的调用将实行动态绑定,其它对虚函数的调用(如对象名加成员选择运算符、虚函数的调用前加类名和作用域运算符)实行静态绑定
示例
#include <iostream.h>
class A
{public:
virtual void f( )
{cout<<"A::f( ) called"<<endl;}
};
class B:public A
{public:
B( ){f( );} //静态绑定
void g( ){f( ); //动态绑定
A::f( ); //静态绑定
}
};
class C:public B
{public:
void f( )
{cout<<"C::f( ) called"<<endl;}
};
main( )
{C c;
c.g( );
return 0;
}
抽象基类和纯虚函数
实现多态性的前提:
1.需要有共同的基类
2.需要在基类中定义共同的接口
3.接口要定义为虚函数
如果基类的接口没办法实现怎么办?
解决方法:
1.不实现这些接口:纯虚函数
2.包含纯虚函数的类:抽象基类
纯虚函数
1.没有函数体的“初始化为0”的函数
//纯虚函数
virtual double area() const = 0;
2.纯虚函数不需要实现,不能被执行
3.通过定义、重定义或继承获得
抽象类和具体类
1.包含纯虚函数(且未对其重定义)的类不能实例化对象,是抽象类
2.如果一个类不是抽象类,则是具体类。
3.抽象类存在的意义是作为其它类的基类,也叫抽象基类
定义或继承获得纯虚函数示例
#include <iostream.h>
class A
{public:
virtual void f( )=0; //纯虚函数定义
};
class B:public A
{public:
B( ){f( );} //静态绑定,错
void g( ){f( ); //动态绑定
A::f( ); //静态绑定,错
}
}; // 类B继承了类A的纯虚函数f,且没有重定义
class C:public B
{public:
void f( )
{cout<<"C::f( ) called"<<endl;}
};
// 类C继承了类A的纯虚函数f,但对f作了重定义
main( )
{C c;
c.g( );
return 0;
}
通过重定义获得纯虚函数示例
#include <iostream.h>
class A
{public:
virtual void f( )
{cout<<"A::f( ) called"<<endl;}
};
class B:public A
{public:
virtual void f( )=0;
//把虚函数f重定义为纯虚函数,virtual可省略
void g( ){f( );}
};
class C:public B
{public:
void f( )
{cout<<"C::f( ) called"<<endl;}
};
// 类C继承了类A的虚函数f和类B的纯虚函数f,
// 但对f作了重定义
main( )
{C c;
c.g( );
return 0;
}
虚析构函数
1.构造函数的执行顺序:从上到下
2.析构函数的执行顺序:从下到上
3.创建对象时要执行正确的构造函数
4.撤销对象时要执行正确的析构函数
动态对象的创建
new ClassName(…);
ClassName指明了要调用的构造函数
动态对象的撤销
delete 基类指针;
如果基类指针指向的是派生类的对象呢?
解决方案:把析构函数定义为虚函数
对于 delete 基类指针; //该类的析构函数为虚函数
程序会根据基类指针指向的对象的类型确定要调用的析构函数
基类的析构函数为虚函数,所有派生类的析构函数都是虚函数
例子一:虚函数与多态性
//文件base.h,定义基类
#if !defined __BASE__H__
#define __BASE__H__
#include <iostream.h>
class Base
{public:
virtual void show( )
{cout<<"I am Base's object!\n";
}
};
#endif
//文件derived.h,定义类Derived
#if !defined __DERIVED__H__
#define __DERIVED__H__
#include "base.h"
class Derived :public Base
{public:
void show()
{cout<<"I am Derived's object!\n";
}
};
#endif
//文件main.cpp,函数调用的动态绑定
#include "derived.h"
main()
{Base *bPtr, bObj;
Derived dObj;
bPtr= &bObj; //基类指针指向基类对象
bPtr->show(); //用指针调用虚函数,动态绑定
bPtr= &dObj; //基类指针指向派生类对象
bPtr->show(); //用指针调用虚函数,动态绑定
return 0;
}
或者
//修改文件main.cpp,用对象引用调用虚函数
#include "derived.h"
main()
{Derived dObj;
Base bObj, &cObj = dObj;
bObj.show(); //用对象调用虚函数,静态绑定
cObj.show();//用对象引用调用虚函数,动态绑定
return 0;
}
例子二:多态性的应用实例
#include <iostream.h>
class shape
{public:
virtual double area(){return 0.0; }
virtual ~shape(){ }
};
double total(shape *s[],int n)
{double sum=0;
for(int i=0;i<n;i++)
sum+=s[i]->area(); //动态绑定
return sum;
}
class triangle: public shape
{protected:
double H,W;
public:
triangle(double h, double w){H=h;W=w;}
double area(){return H*W*0.5;}
};
class rectangle: public triangle
{public:
rectangle(double h, double w)
:triangle(h,w){ }
virtual double area();
};
double rectangle::area(){return H*W;}
class screen
{private:
shape *s[100];
int n;
public:
screen(){n=0;}
void addshapetoscreen(shape *sp)
{if(n<100)n++;
s[n-1]=sp;
}
double total()
{double sum=0;
for(int i=0;i<n;i++)
sum+=s[i]->area();
return sum;
}
};
main()
{shape *s[100];
s[0]=new triangle(2.2,3.3);
s[1]=new rectangle(2.0,4.0);
cout<< total(s,2) << endl;
screen ss;
ss.addshapetoscreen(s[0]);
ss.addshapetoscreen(s[1]);
cout<<ss.total();
for (int i=0;i<2;i++)
delete s[i];
return 0;
}
//增加新的图形不需要修改total函数和screen类
//增加相关图形类
class circle: public shape
{private:
double radius;
public:
circle(double r)
{radius=r;}
double area()
{return radius*radius*3.14159;}
};
//修改主函数
main()
{shape *s[4];
s[0]=new triangle(2.2,3.3);
s[1]=new rectangle(2.0,4.0);
s[2]=new circle(5.0);
s[3]=new circle(8.0);
cout<< total(s,4) <<endl;
screen ss;
ss.addshapetoscreen(s[0]);
ss.addshapetoscreen(s[3]);
cout<<ss.total();
for (int i=0;i<4;i++)
delete s[i];
return 0;
}
例子三:抽象基类的例子
//文件shape.h,定义抽象基类Shape
#if !defined __SHAPE__H__
#define __SHAPE__H__
#include <iostream.h>
class Shape
{public:
virtual double area() const = 0;
virtual void show() const = 0;
};
#endif
//文件circle.h,定义派生类Circle
#if !defined __CIRCLE__H__
#define __CIRCLE__H__
#include "shape.h"
#define PI 3.1416
class Circle :public Shape
{public:
Circle(double = 0.0,
double = 0.0, double = 1.0);
double area() const;
void show() const;
private:
double x,y;
double r;
};
#endif
//文件circle.cpp,实现类Circle
#include "circle.h"
Circle::Circle(double a,
double b, double c)
{ x = a;
y = b;
r = c;
}
double Circle::area() const
{return PI*r*r;
}
void Circle::show() const
{cout<<"I am a Circle: ";
}
// Circle是具体类
//文件rectangle.h,定义派生类Rectangle
#if !defined __RECTANGLE__H__
#define __RECTANGLE__H__
#include "shape.h"
class Rectangle :public Shape
{public:
Rectangle(double = 1.0, double = 1.0);
double area() const;
void show() const;
private:
double length;
double width;
};
#endif
//文件rectangle.cpp,实现类Rectangle
#include "rectangle.h"
Rectangle::Rectangle(double a, double b)
{ length = a;
width = b;
}
double Rectangle::area() const
{
return length*width;
}
void Rectangle::show() const
{
cout<<" I am a Rectangle: ";
} // Rectangle是具体类
//文件main.cpp,测试类Shape的虚函数
#include "circle.h"
#include "rectangle.h"
void callArea(Shape &obj)
{obj.show(); //动态绑定
cout<<"area = "<<obj.area()<<endl;
} // obj.area()动态绑定
main()
{Circle cir(0.0, 0.0, 2.5);
Rectangle rec(2.4, 5.3);
//能用Shape类声明对象吗?
callArea(cir);
callArea(rec);
return 0;
}
例子四:虚析构函数的例子
//文件employee.h,定义基类Employee
#include <iostream.h>
#if !defined __EMPLOYEE__H__
#define __EMPLOYEE__H__
class Employee
{public:
Employee()
{cout<<"Employee begin!"<<endl;
}
virtual ~Employee()
{cout<<"Employee end!"<<endl;
}
};
#endif
//文件programmer.h,定义派生类Programmer
#include <iostream.h>
#include <string.h>
#include "employee.h"
class Programmer: public Employee
{public:
Programmer(char *str)
{cout<<"Programmer begin!"<<endl;
name = new char[strlen(str)+1];
strcpy(name, str);
}
~Programmer()
{delete [] name;
cout<<"Programmer end!"<<endl;
}
private:
char *name;
};
//文件accountant.h,定义派生类Accountant
#include <iostream.h>
#include "employee.h"
class Accountant: public Employee
{public:
Accountant(int n)
{cout<<"Accountant begin!"<<endl;
age = n;
}
~Accountant()
{cout<<"Accountant end!"<<endl;
}
private:
int age;
};
//文件main.cpp
#include "accountant.h"
#include "programmer.h"
const int MAX = 100;
main()
{ int no;
//声明储存雇员信息的数组
Employee *ptr[MAX], *tptr;
int ENum = 0;
char name[100];
int age;
for (int i=0; i<MAX; i++)
ptr[i] = NULL;
//输入雇员信息
cout<<"Input employees' info:"<<endl;
cout<<"1 --- Programmer"<<endl
<<"2 --- Accountant"<<endl
<<"0 --- exit"<<endl;
cin>>no;
while (no)
{switch (no)
{case 1:
cout<<"Please input name:";
cin>>name;
//创建程序员对象
tptr = new Programmer(name);
ptr[ENum++] = tptr;
break;
case 2:
cout<<"Please input his or her age:";
cin>>age;
//创建会计对象
tptr = new Accountant(age);
ptr[ENum++] = tptr;
break;
default:
break;
}
cout<<"Input another employee's info:“
<<endl;
cout<<"1 --- Programmer"<<endl
<<"2 ---Accountant"<<endl
<<"0 --- exit"<<endl;
cin>>no; }
//撤销所有雇员对象
for (i=0; i<ENum; i++)
{
delete ptr[i];
}
return 0;
}