![C++程序设计 第二版 杨长兴 第九章_第1页](http://file4.renrendoc.com/view/cd57de2d74acab575d27a41dc9bbe479/cd57de2d74acab575d27a41dc9bbe4791.gif)
![C++程序设计 第二版 杨长兴 第九章_第2页](http://file4.renrendoc.com/view/cd57de2d74acab575d27a41dc9bbe479/cd57de2d74acab575d27a41dc9bbe4792.gif)
![C++程序设计 第二版 杨长兴 第九章_第3页](http://file4.renrendoc.com/view/cd57de2d74acab575d27a41dc9bbe479/cd57de2d74acab575d27a41dc9bbe4793.gif)
![C++程序设计 第二版 杨长兴 第九章_第4页](http://file4.renrendoc.com/view/cd57de2d74acab575d27a41dc9bbe479/cd57de2d74acab575d27a41dc9bbe4794.gif)
![C++程序设计 第二版 杨长兴 第九章_第5页](http://file4.renrendoc.com/view/cd57de2d74acab575d27a41dc9bbe479/cd57de2d74acab575d27a41dc9bbe4795.gif)
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第9章多态性和虚函数9.1多态性的概念多态性是指不同类的对象对于同一消息的处理具有不同的实现。多态性在C++中表现为同一形式的函数调用,可能调用不同的函数实现。从系统实现的角度看,C++的多态性分为两类,一类称为编译时刻多态性,另一类称为运行时刻多态性,也称动态多态性。9.1.1编译时刻的多态性C++编译时多态性通过重载(函数重载和运算符重载)来实现【例9.1】编译时刻的多态性——运算符重载:下面这段程序建立Rectangle类和Cuboid类,并重载运算符“+=”,使之能用于相应类对象的运算。#include<iostream>usingnamespacestd;classRectangle//定义矩形类{public:
Rectangle(doublew=0,doublel=0); //缺省构造函数
voidset_wl(double
w,doublel);doubleget_w()const;doubleget_l()const;doublearea();~Rectangle(){}; //析构函数
Rectangle&operator+=(Rectangle&rec_add) //重载运算符+={width+=rec_add.width;length+=rec_add.length;return*this; //返回当前对象
}protected:
intwidth;
intlength;};Rectangle::Rectangle(doublew,doublel):width(w),length(l){}voidRectangle::set_wl(double
w,doublel){width=w;length=l;}doubleRectangle::get_w()const{returnwidth;}doubleRectangle::get_l()const{returnlength;}doubleRectangle::area(){returnwidth*length;}classCuboid:publicRectangle//定义长方体类{public:
Cuboid(doublew=0,doublel=0,doubleh=0);voidset_wlh(double
w,double
l,doubleh);doubleget_h()const;doublearea();
Cuboid&operator+=(Cuboid&cub_add){width+=cub_add.width;length+=cub_add.length;height+=cub_add.height;return*this; //返回当前对象
}protected:doubleheight;};Cuboid::Cuboid(double
w,double
l,double
h):Rectangle(w,l),height(h){}voidCuboid::set_wlh(double
w,double
l,doubleh){width=w;length=l;height=h;}doubleCuboid::get_h()const{returnheight;}doubleCuboid::area(){return2*(width*length+width*height+length*height);}//求长方体的表面积intmain(){Rectanglerec1(1,2);Rectanglerec2;
Cuboidcub1(1,2,3);
Cuboidcub2;rec2.set_wl(2,4);cub2.set_wlh(5,10,15);
cout<<"rec1:(width="<<rec1.get_w()<<",length="<<rec1.get_l()<<")"<<endl;
cout<<"rec2:(width="<<rec2.get_w()<<",length="<<rec2.get_l()<<")"<<endl;
rec2+=rec1; //调用Rectangle类的重载运算符:+=
cout<<"rec2.width=("<<rec2.get_w()<<",length="<<rec2.get_l()<<")"<<endl;
cout<<"cub1:(width="<<cub1.get_w()<<",length="<<cub1.get_l()<<",height=";
cout<<cub1.get_h()<<")"<<endl;
cout<<"cub2:(width="<<cub2.get_w()<<",length="<<cub2.get_l()<<",height=";
cout<<cub2.get_h()<<")"<<endl;cub2+=cub1; //调用Cuboid类的重载运算符:+=
cout<<"cub2:(width="<<cub2.get_w()<<",length="<<cub2.get_l()<<",height=";
cout<<cub2.get_h()<<")"<<endl;
cout<<"rec2'sareais"<<rec2.area()<<endl;
cout<<"cub2'sareais"<<cub2.area()<<endl;return0;}9.1.2运行时刻的多态性
运行时刻多态性的实现是指在程序运行过程中根据具体情况来确定调用的是哪一个函数,它是通过动态联编机制实现的【例9.2】运行时刻的多态性运行时的多态性。仍然用例9.1中定义的Rectangle类和Cuboid类。//*************ex9_2.cpp*************//此处加上例9.1中定义的Rectangle类和Cuboid类。intmain(){Rectangle*r;
Cuboidcub3(1,2,3);
cout<<"cub3=("<<cub3.get_w()<<","<<cub3.get_l()<<",";
cout<<cub3.get_h()<<")"<<endl;r=&cub3; //用基类指针指向派生类对象
cout<<"cub3'sareais(*r)"<<r->area()<<endl;
cout<<"cub3'sareais(cub3)"<<cub3.area()<<endl;return0;}程序的运行结果如下:cub3=(1,2,3)cub3'sareais(*r)2cub3'sareais(cub3)22运行时刻的多态性是面向对象的一个非常重要的特征,再来看一个在结构化编程中的例子:【例9.3】下面这段程序是利用多分支结构编程模拟实现绘制图形的函数。//********ex9_3.cpp*********voiddraw(int
obj_figure){switch(obj_figure)
case0://rectangle
draw_rectangle();
//cout<<”drawrectangle”<<endl;
break;
case1://triangle
draw_triangle();
//cout<<”drawtriangle”<<endl;
break;
case2://circle
draw_circle();
//cout<<"draw_circle"<<endl;
break;}这种编程方式使得程序的可维护性和可扩充性都变得很差。那么有没有更好的方法实现上述例子?看看下面的程序段:voiddraw(void*f){
(*f)();}9.2虚函数虚函数的作用 虚函数从表现形式看是指那些被virtual关键字修饰的成员函数。类的一个成员函数如果被说明为虚函数,表明它目前的具体实现仅是一种适用于当前类的实现,而在该类的继承层次链条中有可能重新定义这个成员函数的实现,即这个虚函数可能会被派生类的同名函数所覆盖(override)。例:使用虚函数的例子#include<iostream>usingstd::cout;usingstd::endl;classfigure{public:virtualvoiddraw()//将draw()定义为虚函数{cout<<"drawfigure"<<endl;}};classrectangle:publicfigure{voiddraw(){
cout<<"drawrectangle"<<endl;}};classtriangle:publicfigure{voiddraw(){
cout<<"drawtriangle"<<endl;}};intmain(){figure*f;rectangler1;trianglet1;f=&r1;//基类指针f指向派生类对象r1f->draw();//调用r1的成员函数draw()f=&t1;//基类指针f指向派生类对象t1f->draw();//调用t1的成员函数draw()return0;}程序运行结果:虚函数的使用虚函数的实现机制和调用方式与非虚函数不同,虚函数的使用需要注意以下几点:1.虚函数的声明 只能将类的成员函数声明为虚函数,而不能将类外的普通函数声明为虚函数。虚函数的作用是允许在派生类中对基类的虚函数重新定义,因而它只能用于类的继承层次结构中。2.虚函数的访问权限 派生类中虚函数的访问权限并不影响虚函数的动态联编,如下面的例9.5,其中派生类CDerived中重新定义了虚函数F4(),在程序的运行中由于虚函数的机制,在CBase::F3()中调用F4()时会调用CDerived::F4(),而该函数的访问权限是私有的。3.成员函数中调用虚函数 在类的成员函数中可以直接调用相应类中定义或重新定义的虚函数,分析这类函数的调用次序时要注意成员函数的调用一般是隐式调用,应该将其看成是通过this指针的显式调用。【例9.5】在成员函数中调用虚函数//*********ex9_5.cpp***********#include<iostream>usingnamespacestd;classCBase{public:voidF1(){
cout<<"=>CBase-F1=>";F2();}voidF2(){
cout<<"CBase-F2=>";F3();}virtualvoidF3(){
cout<<"CBase-F3=>";F4();//即this->F4()}virtualvoidF4(){
cout<<"CBase-F4=>";}};classCDerived:public
CBase{private:virtualvoidF4(){
cout<<"Derived-F4=>out"<<endl;}public:voidF1(){
cout<<"=>Derived-F1=>";CBase::F2();}voidF2(){
cout<<"=>Derived-F2=>";F3();//即this->F3()}};intmain(){
CBase*pB;
CDerived
Obj;程序运行结果:
pB=&Obj;
pB->F1();Obj.F1();return0;}9.3纯虚函数与抽象类纯虚函数在程序设计中,通常会在类层次的顶层以虚函数的形式给出该类层次所提供的某些操作的统一接口,由于层次较高,有些操作无法(也无必要)给出具体的实现,对于这种情况可以不对虚函数的实现进行定义,而将它们说明为纯虚函数。纯虚函数是在声明虚函数时被“初始化”为0的函数。声明纯虚函数的一般形式是:virtual<函数类型><函数名>(参数表列)=0;抽象类具有纯虚函数的类无法用于创建对象,因为它的纯虚函数无函数体,所以又把这种含有纯虚函数的类称为抽象类。抽象类的主要作用是为一个族类提供统一的公共接口,用户在这个基础上根据自己的需要定义出功能各异的派生类,以有效地发挥多态的特性。使用抽象类时应注意以下问题:⑴抽象类只能用作其它类的基类,不能建立抽象类的对象。因为它的纯虚函数没有定义功能。⑵抽象类不能用作参数类型、函数的返回类型或显式转换的类型。⑶可以声明抽象类的指针和引用,通过它们,可以指向并访问派生类对象,从而访问派生类的成员。⑷如果在抽象类所派生出的新类中对基类的所有纯虚函数进行了定义,那么这些函数就被赋予了功能,可以被调用。这个派生类就不是抽象类,而是可以用来定义对象的具体类。如果在派生类中没有对所有纯虚函数进行定义,则此派生类仍然是抽象类,不能用来定义对象。9.4抽象类的实例一个抽象类就是一个界面。类层次结构是一种逐步递增地建立类的方式。有些抽象类也提供了重要的功能,支持进一步向上构造。类层次结构中的各个类一方面为用户提供了有用的功能,同时也作为实现更高级或者更特殊的类的构造块。这种层次结构对于支持以逐步求精方式进行的程序设计是非常理想的。【例9.10】抽象类实例#include<iostream>usingnamespacestd;classCShape{//定义为一个抽象类,即一个图形界面接口public:virtualdoublearea()const{return0.0;}//定义为虚函数,允许后面覆盖
virtualvoidprintShapeName()const=0;//定义为纯虚函数,由派生类负责实现
virtualvoiddraw()const=0;//定义为纯虚函数};classCPoint:public
CShape//公有继承CShape{public:
CPoint(int=0,int=0);//声明构造函数
voidsetPoint(int,int);
int
getX()const{returnx;}
int
getY()const{returny;}virtualvoidprintShapeName()const//覆盖CShape基类的纯虚函数
{cout<<"Point:";}virtualvoiddraw()const;private:
int
x,y;};CPoint::CPoint(int
a,intb)//CPoint构造函数的实现{setPoint(a,b);}voidCPoint::setPoint(int
a,intb){x=a;y=b;}voidCPoint::draw()const{cout<<"["<<x<<","<<y<<"]";}classCCircle:public
CPoint{public:
CCircle(doubler=0.0,intx=0,inty=0);voidsetRadius(double);doublegetRadius()const;virtualdoublearea()const;virtualvoidprintShapeName()const{cout<<"Circle:";}virtualvoiddraw()const;private:doubleradius;};CCircle::CCircle(double
r,int
a,int
b):CPoint(a,b){setRadius(r);}voidCCircle::setRadius(doubler){radius=r>0?r:0;}doubleCCircle::getRadius()const{returnradius;}doubleCCircle::area()const{return3.1415926*radius*radius;}voidCCircle::draw()const{
CPoint::draw();
cout<<";Radius="<<radius;}classCRectangle:public
CPoint{public:
CRectangle(doublewidth=0.0,doubleheight=0.0,intx=0,inty=0);voidsetWidth(double);doublegetWidth();voidsetHeight(double);doublegetHeight();virtualdoublearea()const;virtualvoidprintShapeName()const{cout<<"Rectangle:";}virtualvoiddraw()const;private:doublewidth;doubleheight;};CRectangle::CRectangle(double
w,double
h,intx,inty):CPoint(x,y){setWidth(w);
setHeight(h);}voidCRectangle::setWidth(doublew){width=w>0?w:0;}voidCRectangle::setHeight(doubleh){height=h>0?h:0;}doubleCRectangle::getWidth(){returnwidth;}doubleCRectangle::getHeight(){returnheight;}doubleCRectangle::area()const{returnwidth*height;}voidCRectangle::draw()const{CPoint::draw();
cout<<"width="<<width<<";Height="<<height;}voidViaPointer(const
CShape*);voidViaReference(const
CShape&);intmain(){
CPointpoint(5,9);//定义point对象并初始化
CCirclecircle(4.5,14,8);//定义circle对象并初始化
CRectanglerectangle(12,3.5,8,9);//定义rectangle对象并初始化
point.printShapeName();//静态绑定
point.draw();//静态绑定
cout<<endl;
circle.printShapeName();//静态绑定
circle.draw();//静态绑定
cout<<endl;
rectangle.printShapeName(
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 《电镀液性能》课件
- 2025年长沙货运从业资格证考试题目大全及答案
- 企业文化与财务管理模板
- 咨询业态势剖析模板
- 师专外国文学教学改革的探索
- 小学语文低年段“说写融合”的要求及教学策略
- 安全运维管理中的密码管理
- 考学个人申请书
- 申请医保申请书
- 大学生创业项目支出明细
- 超融合架构与传统架构对比解析方案
- 少儿美术课件- 9-12岁 素描班《场景素描》
- 剪映:手机短视频制作-配套课件
- 金融工程.郑振龙(全套课件560P)
- 血液透析的医疗质量管理与持续改进
- 桥式起重机日常检查保养记录表
- 五年级小数乘法竖式计算300道(可直接打印)
- 半导体制造技术导论
- 英语演讲技巧和欣赏课件
- 物流托运单模板
- CNC设备具体参数
评论
0/150
提交评论