第12章 多态性与虚函数 12.1多态性的概念 12.2一个典型的例子 12.3虚函数 12.4纯虚函数与抽象类
第12章 多态性与虚函数 12.1 多态性的概念 12.2 一个典型的例子 12.3 虚函数 12.4 纯虚函数与抽象类
12.1多态性的 多态性(polymorphism):是面向对象程序设计的 一个重要特征。利用多态性可以设计和实现一个 易于扩展的系统 C++程序设计中的多态性 ↓ 是指具有不同功能的函 实现用一个函数名调 数可以用同一个函数名 用不同内容的函数 面向对象方法多态性的表述:向不同的对象发送同一个 消息,不同的对象在接收时会产生不同的行为(即方法) 每个对象可以用自己的方式去响应共同的消息
12.1 多态性的 多态性(polymorphism) 概念:是面向对象程序设计的 一个重要特征。利用多态性可以设计和实现一个 易于扩展的系统 C++程序设计中的多态性 是指具有不同功能的函 数可以用同一个函数名 实现用一个函数名调 用不同内容的函数 面向对象方法多态性的表述:向不同的对象发送同一个 消息,不同的对象在接收时会产生不同的行为(即方法) 每个对象可以用自己的方式去响应共同的消息
在C++程序设计中,在不同的类中定义了其响应消息的方法, 则使用这些类时,不必考虑它们是何类型,只要发布消息即可 函数重 静 状 在程序编译时系统就 态 运算符重载 能决定调用的是哪个 函数 多态性分类 又称编译时的多态性 在程序运行过程中才动态地确定 动态 操作所针对的对象,它又称运行 时的多态性 通过虚函数(virtual function)实现的 在本章中主要介绍动态多态性和虚函数
在本章中主要介绍动态多态性和虚函数。 在C++程序设计中,在不同的类中定义了其响应消息的方法, 则使用这些类时,不必考虑它们是何类型,只要发布消息即可 多态性分类 静 态 动态 函数重 载运算符重载 在程序编译时系统就 能决定调用的是哪个 函数 又称编译时的多态性 在程序运行过程中才动态地确定 操作所针对的对象,它又称运行 时的多态性 通过虚函数(virtual function)实现的
要研究的问题 当一个基类被继承为 在运行时用同一个 不同的派生类时,各 成员名调用类对象 派生类可以使用与基 的成员,会调用哪 类成员相同的成员名 个对象的成员? 与基类成员同 相关的不同 通过继承而产生 名的成员在不 的派生类 同的派生类中 有不同的含义 多态性是“一个接口,多种方法
多态性是“一个接口,多种方法” 。 要研究的问题 当一个基类被继承为 不同的派生类时,各 派生类可以使用与基 类成员相同的成员名 在运行时用同一个 成员名调用类对象 的成员,会调用哪 个对象的成员? 通过继承而产生 相关的不同 的派生类 与基类成员同 名的成员在不 同的派生类中 有不同的含义
12.2 一个典型的 多态性的 个承上启下的例子孔 综合 一个基础 运算符重载 应用 用例 例12.1先建立一个Point(点)类,包含数据成员 x,y(坐标点)。以它为基类,派生出一个Circle(圆)类, 增加数据成员r(半径),再以Circle类为直接基类, 派生出一个Cylindere(圆柱体)类,再增加数据成员 (高)。要求编写程序,重载运算符“>”,使之能用于输出以上类对象
12.2 一个典型的 例子 例12.1 先建立一个Point(点)类,包含数据成员 x,y(坐标点)。以它为基类,派生出一个Circle(圆)类, 增加数据成员r(半径),再以Circle类为直接基类, 派生出一个Cylinder(圆柱体)类,再增加数据成员 h(高)。要求编写程序,重载运算符“>”,使之能用于输出以上类对象。 一个承上启下的例子 继 承运算符重载 综合 应用 多态性的 一个基础 用例
对于一个比较大的程序,应当分成若干步骤进行。 先声明基类,再声明派生类,逐级进行,分步调试 声明基类Point类 #include〈iostream) friend ostream //声明类Point operator<<(ostream class Point &const Point &) (public: /重载运算符“<” Point(float x=0,float y=0); protected: /有默认参数的构造函数 /1受保护成员 void setPoint(float,float); float x,y; /设置坐标值 }; float getx() const{return x;}/读x坐标 float gety() const {return y;}/读y坐标
声明基类Point类 #include //声明类Point class Point {public: Point(float x=0,float y=0); //有默认参数的构造函数 void setPoint(float,float); //设置坐标值 float getx( ) const{return x;}//读x坐标 float gety( ) const {return y;}//读y坐标 对于一个比较大的程序,应当分成若干步骤进行。 先声明基类,再声明派生类,逐级进行,分步调试 friend ostream & operator<<(ostream &,const Point &); //重载运算符“<<” protected: //受保护成员 float x,y; };
//Point的构造函数 Point:Point(float a,float b) //对x,y初始化 {x=a;y=b;} /设置x和y的坐标值 void Point:setPoint(float a,float b)/为x,y赋新值 {x=a;y=b;} /重载运算符“<”,使之能输出点的坐标 ostream operator<<(ostream &output,const Point &p) output<<"["<<p.x<<","<<p.y<"]"<<endl; return output; } 以上完成了基类Point类的声明
//Point的构造函数 Point::Point(float a,float b) //对x,y初始化 {x=a;y=b;} //设置x和y的坐标值 void Point::setPoint(float a,float b)//为x,y赋新值 {x=a;y=b;} //重载运算符“<<”,使之能输出点的坐标 ostream & operator<<(ostream &output,const Point &p) {output<<″[″<<p.x<<″,″<<p.y<<″]″<<endl; return output; } 以上完成了基类Point类的声明
现在要对上面写的基类声明进行调试,检查它是否有错, 为此要写出main函数。实际上它是一个测试程序。 int main() {Point p(3.5,6.4);/建立Pointa类对象p cout<<"x="<<p.getx()<<",y="<<p.gety()<<endl; /输出p的坐标值 p.setPoint(8.5,6.8);/重新设置p的坐标值 cout<<"p(new):"<<p<<endl; /用重载运算符“<”输出p点坐标 运行结果为 测试程序检查了基类中各函数的功 X=3.5,y=6.4 能,以及运算符重载的作用,证明 p(new):8.5,6.81 程序是正确的
现在要对上面写的基类声明进行调试,检查它是否有错, 为此要写出main函数。实际上它是一个测试程序。 int main( ) {Point p(3.5,6.4); //建立Point类对象p cout<<″x=″<<p.getX( )<<″,y=″<<p.getY( )<<endl; //输出p的坐标值 p.setPoint(8.5,6.8); //重新设置p的坐标值 cout<<″p(new):″<<p<<endl; //用重载运算符“<<”输出p点坐标 } 运行结果为 x=3.5,y=6.4 p(new):[8.5,6.8] 测试程序检查了基类中各函数的功 能,以及运算符重载的作用,证明 程序是正确的
(2) 声明派生类Circle 在上面的基础上,再写出声明派生类Circle的部分: class Circle:public Point /circle是Point类的公用派生类 {public: Circle(f1oatx=0,float y=0,float ra=0);/构造函数 void setRadius(float);/设置半径值 float getRadius()const;//读取半径值 float area()const;/计算圆面积 friend ostream &operator<<(ostream &const Circle & /重载运算符“<” private: float radius; };
(2) 声明派生类Circle 在上面的基础上,再写出声明派生类Circle的部分: class Circle:public Point //circle是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 &); //重载运算符“<<” 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; /计算圆面积 float Circle:area()const {return 3.14159*radius*radius; /重载运算符“<”,使之按规定的形式输出圆的信息 ostream &operator<<(ostream &output,const Circle &c) {output<<"Center=["<<c.x<<","<<c.y<<"]r="<<c.ra dius<<",area="<<c.area()<<endl; return output;
//定义构造函数,对圆心坐标和半径初始化 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;} //计算圆面积 float Circle::area( ) const {return 3.14159*radius*radius;} //重载运算符“<<”,使之按规定的形式输出圆的信息 ostream &operator<<(ostream &output,const Circle &c) {output<<″Center=[″<<c.x<<″,″<<c.y<<″],r=″<<c.ra dius<<″,area=″<<c.area( )<<endl; return output; }