C++程序设计基础教程 第2版 课件 第12章 虚函数与多态性_第1页
C++程序设计基础教程 第2版 课件 第12章 虚函数与多态性_第2页
C++程序设计基础教程 第2版 课件 第12章 虚函数与多态性_第3页
C++程序设计基础教程 第2版 课件 第12章 虚函数与多态性_第4页
C++程序设计基础教程 第2版 课件 第12章 虚函数与多态性_第5页
已阅读5页,还剩33页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第12章多态性与虚函数主要内容12.1 多态性的概念12.2虚函数的定义12.3纯虚函数与抽象类12.4应用实例12.1多态性的概念多态性是面向对象程序设计的重要特征之一。多态性是指发出同样的消息被不同类型的对象接收时导致完全不同的行为。

“一个接口,多种方法”多态的实现:函数重载运算符重载虚函数类模板引例classPoint{public:

Point(doublei,doublej){x=i;y=j;}

double

Area()const{return0.0;}private:

doublex,y;};classRectangle:publicPoint{public:

Rectangle(doublei,doublej,doublek,doublel);

doubleArea()const{returnw*h;}private:

doublew,h;};Rectangle::Rectangle(doublei,doublej,doublek,doublel):Point(i,j){ w=k;h=l;}voidfun(Point&s){ cout<<"Area="<<s.Area()<<endl;}voidmain(){

Rectanglerec(3.0,5.2,15.0,25.0); fun(rec);}运行结果:Area=0.0classPoint{public:

Point(doublei,doublej){x=i;y=j;}

virtualdoubleArea()const{return0.0;}private:

doublex,y;};classRectangle:publicPoint{public:

Rectangle(doublei,doublej,doublek,doublel);

virtualdoubleArea()const{returnw*h;}private:

doublew,h;};//其它函数同上例voidfun(Point&s){ cout<<"Area="<<s.Area()<<endl;}voidmain(){

Rectanglerec(3.0,5.2,15.0,25.0); fun(rec);}?运行结果:Area=37512.2虚函数的定义12.2.1引入虚函数的原因虚函数的作用是允许在派生类中重新定义与基类同名的函数,并且可以通过基类指针(或引用)来访问基类和派生类中的同名函数。根据基类指针指向的对象调用该对象的成员函数.12.2.2虚函数的定义和使用虚函数是非静态的成员函数。其说明格式为:virtual<类型说明符><函数名>(<参数表>)即在类的说明中,在函数原型之前加virtual。注意:virtual

只用在类定义的原型说明中,不能用在函数实现中。具有继承性,基类中定义了虚函数,派生类中无论是否说明,同原型函数都自动为虚函数。本质:不是重载定义而是覆盖定义。调用方式:通过基类指针或引用,执行时会根据指针指向的对象的类,决定调用哪个函数。【例12-2】使用虚函数的例子。classBase{private: intx,y;public: Base(intxx=0,intyy=0) {x=xx;y=yy;} virtualvoidview() {cout<<"Base:"<<x<<""<<y<<endl;}};classSubbase:publicBase{private: intz;public: Subbase(intxx,intyy,intzz):Base(xx,yy) {z=zz;} voidview(){cout<<"Subbase:"<<z<<endl;}};intmain(){ Baseobj(1,2),*objp; Subbasesubobj(3,4,5); objp=&obj; objp->view(); objp=&subobj; objp->view();return0;}运行结果:Base:12Subbase:5【例12-3】虚函数传递性的例子。classB0{public:

virtualvoiddisplay()//虚函数

{cout<<"B0::display()"<<endl;}};classB1:publicB0{public: voiddisplay()//自动成为虚函数

{cout<<"B1::display()"<<endl;}};classD1:publicB1{public: voiddisplay()//自动成为虚函数

{cout<<"D1::display()"<<endl;}};intmain() { B0b0,*p; B1b1; D1d1; p=&b0; p->display(); p=&b1; p->display(); p=&d1; p->display(); return0;}运行结果:B0::display()B1::display()D1::display()12.2.3虚函数的限制使用虚函数时应注意如下问题:(1)虚函数的声明只能出现在类声明的函数原型的声明中,不能出现在函数体实现中,同时基类中只有保护成员或公有成员才能被声明为虚函数。(2)在派生类中重新定义虚函数时,关键字virtual可以写也可不写,但在容易引起混乱时,应写上该关键字。(3)动态联编只能通过指针、引用或其他成员函数来访问虚函数,如果用对象名的形式来访问虚函数,将采用静态联编。(4)虚函数必须是所在类的成员函数,不能是友元函数或静态成员函数。但可以在另一个类中被声明为友元函数。(5)构造函数不能声明为虚函数,析构函数可以声明为虚函数。(6)由于内联函数不能在运行中动态确定其位置,所以它不能声明为虚函数。12.3纯虚函数与抽象类12.3.1纯虚函数纯虚函数是一个在基类中说明的虚函数,在基类中没有定义具体的操作内容,要求派生类根据需要定义自己的版本。纯虚函数的声明格式: virtual函数类型函数名(参数表)=0;声明为纯虚函数后,基类中就不再给出函数的实现部分,纯虚函数的函数体由各派生类自己给出。注意区分函数体为空的虚函数与纯虚函数的区别。【例12-4】设计一个图形基类(Shape类),由其直接派生出circle类和间接派生出cylinder类,派生类中都包含求面积函数area()和求体积函数volume()。要求采用多态技术,在主函数中通过指向基类的指针,调用area()和volume()函数,实现求得不同形状的图形面积和体积。#include<iostream>usingnamespacestd;classShape{public:virtualvoidset()=0;virtualdoublearea()=0;virtualdoublevolume()=0;};classCircle:publicShape{protected:doubleradius;public:Circle(){radius=0;}virtualvoidset()

{cout<<"inputnewradius:";cin>>radius;}virtualdoublearea(){return3.14*radius*radius;}

virtualdoublevolume(){return0.0;}};classCylinder:publicCircle{protected:doubleheight;public:Cylinder(){height=0;}virtualvoidset(){Circle::set();cout<<"inputnewheight:";cin>>height;}virtualdoublearea(){return2*3.14*radius*(radius+height);}virtualdoublevolume(){return3.14*radius*radius*height;}};intmain(){Shape*p;Circlecl;p=&cl;p->set();cout<<"Circle'sarea:"<<p->area()<<endl;cout<<"Circle'svolume:"<<p->volume()<<endl;Cylindercy;p=&cy;p->set();cout<<"Cylinder'sarea:"<<p->area()<<endl;cout<<"Cylinder'svolume:"<<p->volume()<<endl;return0;}运行结果:inputnewradius:3↙Circle'sarea:28.26Circle'svolume:0inputnewradius:2↙inputnewheight:5↙Cylinder'sarea:87.92Cylinder'svolume:62.812.3.2抽象类带有纯虚函数的类是抽象类。抽象类是一种特殊的类,为抽象和设计的目的而建立,处于继承层次结构的较上层。其作用是将有关的数据和行为组织在一个继承层次结构中,保证派生类具有要求的行为。抽象类描述了一组子类共同的操作接口,而完整的实现留给了子类。抽象类只能作为基类使用,不能实例化。但是可以声明抽象类的指针和引用,指向并访问派生类的对象。对于暂时无法实现的函数,可以声明为纯虚函数,留给派生类去实现。抽象类的一般形式class类名

{

virtual

类型函数名(参数表)=0;//纯虚函数

...}抽象类使用注意事项抽象类派生出新的类后,如果派生类给出所有纯虚函数的实现,就不再是抽象类,可以实例化;否则就还是抽象类当派生类中没有重新定义抽象类中的纯虚函数时,必须继续声明这些函数为纯虚函数含有纯虚函数的抽象类也可以定义其它非纯虚的虚函数。虽然程序中不能定义该类的对象,但如果派生类中直接继承这些一般虚函数,则还可以通过派生类的对象来调用这些一般的虚函数【例12-5】对【例12-4】进行改造,重载运算符“<<”和“>>”,使之成为通用接口。classShape{public:virtualvoidset()=0;virtualdoublearea()=0;virtualdoublevolume()=0;};istream&operator>>(istream&mycin,Shape&p){ p.set();

returnmycin;}ostream&operator<<(ostream&mycout,Shape&p){ mycout<<"area:"<<p.area()<<endl;

mycout<<"volume:"<<p.volume()<<endl;

returnmycout;}intmain(){Circlecl;cin>>cl;cout<<cl;Cylindercy;cin>>cy;cout<<cy;return0;}运行结果:inputnewradius:3↙area:28.26volume:0inputnewradius:3↙inputnewheight:6↙area:169.56volume:169.5612.4应用实例【例12-6】小明经营着一家宠物店,目前能够接收的宠物种类有猫和狗,他希望设计一个宠物信息管理系统,能够记录顾客送来的宠物姓名,能够展示当前店里的所有宠物的姓名。(1)声明基类Animal类,其没有具体的动作,故可以声明为抽象类:#include<iostream>#include<cstring>usingnamespacestd;classAnimal{public: virtualvoidPrintName()=0;};(2)由基类Animal类派生出Cat类和Dog类:classCat:publicAnimal{ charCName[20];public: Cat(char*Name) {strcpy(CName,Name);} voidPrintName() {cout<<CName<<endl;}};classDog:publicAnimal{ charDName[20];public: Dog(char*Name) {strcpy(DName,Name);} voidPrintName() {cout<<DName<<endl;}};(3)声明宠物店类,实现添加和展示宠物信息:classHome{ intnAnimals; Animal*pAnimal[20];public:Home(){ inti;

for(i=0;i<20;i++)

pAni

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论