面向对象程序设计语言C++第07章-虚函数和多态性市公开课一等奖省赛课获奖_第1页
面向对象程序设计语言C++第07章-虚函数和多态性市公开课一等奖省赛课获奖_第2页
面向对象程序设计语言C++第07章-虚函数和多态性市公开课一等奖省赛课获奖_第3页
面向对象程序设计语言C++第07章-虚函数和多态性市公开课一等奖省赛课获奖_第4页
面向对象程序设计语言C++第07章-虚函数和多态性市公开课一等奖省赛课获奖_第5页
已阅读5页,还剩45页未读 继续免费阅读

付费下载

下载本文档

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

文档简介

面向对象程序设计语言C++电子科技大学计算机学院1第1页第七章虚函数和多态性C++使用多态性实现同一个消息,不一样接收者采取不一样响应方式这种现象。多态性是一个事务有各种形态。在面向对象语言中,普通这么描述多态:向不一样对象发送同一个消息,不一样对象在接收时会产生不一样行为。也就是说,每个对象能够用自己方式去响应共同消息。2第2页第七章虚函数和多态性C++语言多态性有两种类型:

静态多态性和动态多态性。函数重载和运算符重载都是静态多态性。在程序编译时系统就能够决定调用哪个函数,所以静态多态性又称为编译时多态性。动态多态性时程序运行过程中才动态确实定操作所针正确对象。它又称为运行时多态性。动态多态性是经过虚函数实现。3第3页第七章虚函数和多态性7.1虚函数7.1.1静态多态性对于普通组员函数重载,可表示为下面方式:(1)在同一个类中重载;(2)在不一样类中重载;(3)基类组员函数在派生类中重载;所以,重载函数访问是在编译时区分,这种程序运行之前就能够在多个函数中确定当前访问函数方法称为静态多态性。4第4页第七章虚函数和多态性7.1虚函数7.1.1静态多态性有以下三种区分方法:据参数特征加以区分,比如:Show(int,

char)与

Show(char*,

float)使用”::”加以区分,比如:Circle::Show有别于

Point::Show依据类对象加以区分ACircle.Show()调用

Circle::Show()5第5页第七章虚函数和多态性7.1虚函数7.1.1静态多态性子类能够重载父类组员:classA{public: voidfun()

{cout<<"InA"<<endl;}};classB

:

publicA{public: voidfun()

{cout<<"InB"<<endl;}};6第6页第七章虚函数和多态性7.1虚函数7.1.1静态多态性

CCobj; Cobj.fun();

//调用C::fun() Cobj.B::fun();//调用B::fun() Cobj.A::fun();//调用A::fun() A&Aref=Cobj; Aref.fun();

//调用A::fun(),编译器经过类型确定调用哪个版本

B&Bref=Cobj; Bref.fun();

//调用B::fun() Bref.A::fun();//调用A::fun() A*Apointer=&Cobj; Apointer->fun();//调用A::fun()7第7页第七章虚函数和多态性7.1虚函数7.1.2基类和派生类指针与对象关系(1)能够用指向基类指针指向其公有派生类对象基类指针访问是派生对象拥有基类部分,派生类本身部分不能被基类指针访问。指向派生类指针指向基类对象是不正确

(2)希望用基类指针访问其公有派生类特定组员,必须将基类指针用显示类型转换为派生类指针。8第8页第七章虚函数和多态性7.1虚函数7.1.3虚函数与多态性1.虚函数概念

一个指向基类指针可用来指向从基类公有派生任何对象。是

C++实现运行时多态性关键路径。假如有多个或者多层派生类,经过一个基类指针能够访问全部派生类对象组员函数,这么就能够实现一个接口,多个实现访问了。9第9页第七章虚函数和多态性7.1虚函数7.1.3虚函数与多态性classBase{public: Base(inta){x=a;}

voidwho()

{cout<<"base"<<x<<"\n";}protected: intx;};10classFirst_d:publicBase{public:First_d(inta):Base(a){}voidwho()

{cout<<"Firstderivation"<<x<<"\n";}};classSec_d:publicBase{public:Sec_d(inta):Base(a)

{}voidwho()

{cout<<"Secondderivation"<<x<<"\n";}};第10页第七章虚函数和多态性7.1虚函数7.1.3虚函数与多态性

Base*p; Basebase_obj(1); First_dfirst_obj(2); Sec_dsecond_obj(3);

p=&base_obj; p->who(); p=&first_obj; p->who();

p=&sec_obj; p->who();输出?11第11页第七章虚函数和多态性7.1虚函数7.1.3虚函数与多态性程序输出是:

base1base2base3调用都是父类函数版本12第12页第七章虚函数和多态性7.1虚函数7.1.3虚函数与多态性经过父类指针来看,该指针所指向是父类对象。13x&Base::who()&First_d::who()p对于p是不可见第13页第七章虚函数和多态性7.1虚函数7.1.3虚函数与多态性假如伴随p所指向对象不一样,p->who()能调用不一样类中who()版本,这么就能够用一个界面访问多个实现版本。实际上,这表示了一个动态性质,函数调用依赖于运行时p所指向对象。

虚函数提供就是这种解释机制。虚函数是在基类中被冠以virtual组员函数,它提供了一个接口界面。14第14页第七章虚函数和多态性7.1虚函数7.1.3虚函数与多态性虚函数能够在一个或多个派生类中被重新定义,但要求在派生类中重新定义时,虚函数函数原型(包含返回类型,函数名,参数个数,参数类型次序)必须完全相同。重写上例。15第15页第七章虚函数和多态性7.1虚函数7.1.3虚函数与多态性classBase{public: Base(inta){x=a;}

virtual

voidwho()

{cout<<"base"<<x<<"\n";}protected: intx;};16classFirst_d:publicBase{public:First_d(inta):Base(a){}voidwho()

{cout<<"Firstderivation"<<x<<"\n";}};classSec_d:publicBase{public:Sec_d(inta):Base(a)

{}voidwho()

{cout<<"Secondderivation"<<x<<"\n";}};第16页第七章虚函数和多态性7.1虚函数2.运行时多态性与虚特征(1)运行时多态性在带有虚函数类中,编译器设置一个指针,称为虚指针vpointer(缩写为VPTR)。编译器对每个包含虚函数类创建一个虚表(称为VTABLE),存放类虚函数地址。VPTR指向这个对象VTABLE。经过基类指针做虚函数调用时,编译器取得这个VPTR,找到该类VTABLE,并在其中查找对应虚函数地址,完成动态匹配。17第17页第七章虚函数和多态性7.1虚函数18第18页单界面、多实现classfigure

{protected:floatx,y;

public:

voidset_dim(floati,floatj=0)

{x=i;

y=j;}

virtualvoidshow_area()

{cout<<“Noarea\n”;

}

};

第19页classtriangle:

publicfigure

{public:

voidshow_area()

{cout<<x*0.5*y<<“\n”;}

};

第20页

classsquare:

publicfigure{

public:

voidshow_area()

{cout<<x*y<<“\n”;

}

};

第21页classcircle:

publicfigure

{

public:

voidshow_area()

{

cout<<3.14*x*x;

}

};

第22页voidmain()

{

figure*p;trianglet;squares;circlec;

p=&t;

p->set_dim(10.0,

5.0);

p->show_area();p=&s;

p->set_dim(10.0,

5.0);

p->show_area();

p=&c;

p->set_dim(9.0);

p->show_area();

}

第23页各个派生类共享基类函数set_dim(floati,floatj=0);而对于计算面积,各个实际图形有不一样算法square、triangle和circle含有相同界面show_area()但它们对应不一样实现方法所以,函数show_area()定义为虚函数。第24页第七章虚函数和多态性7.1虚函数

一个组员函数什么时候需要申明为虚函数呢?首先考虑组员函数所在类是否会做为基类。然后看组员函数在类继承后有没有功效被修改?假如希望修改其功效,普通将它申明为虚函数。还应该考虑对组员函数调用是经过对象名还是基类指针或引用去访问。假如经过基类指针或引用去访问,则申明为虚函数。25第25页第26页第七章虚函数和多态性7.1虚函数(2)虚特征用虚函数实现运行时多态性关键之处是,必须用指向基类指针(或者引用)访问虚函数。尽管能够像调用其它组员函数那样显式地用对象名来调用一个虚函数,但只有在一个指向基类指针(或者引用)访问虚函数时,运行时多态性才能实现。这时,称为函数含有虚特征。27第27页第七章虚函数和多态性7.1虚函数基类函数含有虚特征条件是:在基类中,将该函数说明为虚(virtual)函数。这么能够在派生类中重新定义此函数,为它赋予新功效,并能够方便调用。在类外定义虚函数时,无须再加virtual关键字。定义基类公有派生类;在基类公有派生类中原型一致地重载该虚函数;定义指向基类指针变量,它指向基类公有派生类对象(或定义基类引用,它引用基类公有派生类对象)。28第28页第七章虚函数和多态性7.1虚函数重载一个虚函数时,要求函数名、返回类型、参量个数、参数类型和次序是完全相同。假如不一样,会产生什么情况呢?(1)仅仅返回类型不一样,其余相同。C++认为这是错误,因为仅仅返回类型不一样函数本质上是含糊。(2)函数原型不一样,仅函数名相同,C++认为这是普通函数重载,此时虚特征丢失。(例7-5)29第29页第七章虚函数和多态性7.1虚函数定义虚函数时需要注意:(1)虚函数必须是类组员函数。不能将虚函数说明为全局(非组员)函数,也不能说明为静态组员函数。不能将友元说明为虚函数,但虚函数能够是另一个类友元。(2)析构函数能够是虚函数,但结构函数不能为虚函数。(3)一旦一个函数被说明为虚函数,不论经历了多少派生类层,都将保持其虚特征。30第30页第七章虚函数和多态性7.1虚函数3.虚析构函数请看这个例子:classbase{public: base(){cout<<"base()"<<endl;} ~base(){cout<<"~base()"<<endl;}};classderived:publicbase{public: derived(){cout<<"derived()"<<endl;} ~derived(){cout<<"~derived()"<<endl;}};31intmain(){

base*pb=newderived;

deletepb;

return0;}第31页第七章虚函数和多态性7.1虚函数请问程序输出是什么?32程序输出以下:base()derived();~base();结构函数base()和derived()都被调用了,不过析构函数只有~base()调用了。第32页第七章虚函数和多态性7.1虚函数原因很简单:基类指针只调用基类组员函数,不能够调用派生类组员函数,即使是析构函数也是如此。假如希望能够执行派生类析构函数,则需要将基类析构函数申明为虚析构函数:virtual~base()

{cout<<"~base()"<<endl;}当基类析构函数申明为虚函数时,不论指针指向是同一类族中哪一个对象,当对象撤消时,系统会采取动态关联,调用对应析构函数,对该对象进行清理工作。33第33页

假如希望经过基类指针或者引用访问派生类组员函数,但基类功效比较抽象或者不能确定功效,能够将基类定义为抽象类,即只定义函数名字,没有函数体,详细功效由派生类添加第34页第七章虚函数和多态性7.2纯虚函数和抽象类基类往往表示一些抽象概念。比如,shape是一个基类,它表示含有形状东西,从shape能够派生出封闭图形和非封闭图形两个派生类。封闭图形又能够派生出椭圆形、多边形,……这个类等级基类shape表达了一个抽象概念在shape中定义一个求面积函数显然是无意义但能够将其说明为虚函数,提供各派生类一个公共界面,并由各派生类提供求面积函数各自版本35第35页第七章虚函数和多态性7.2纯虚函数和抽象类基类有些虚函数没有定义是很正常,不过要求派生类必须重定义这些虚函数,以使派生类有意义。为此,C++引入了纯虚函数概念。纯虚函数是一个在基类中说明虚函数,它在该基类中没有定义,要求任何派生类都必须定义自己版本。为说明一纯虚函数,使用以下普通形式:virtualtypefunc_name(参数表)=0;36第36页第七章虚函数和多态性7.2纯虚函数和抽象类将一虚函数说明成纯虚函数,就要求任何派生类都应该定义自己实现。在结构函数和析构函数中调用虚函数时,采取静态联编,所以,在结构函数和析构函数中不能够调用纯虚函数。但其它组员函数能够调用纯虚函数。假如一个类最少有一个纯虚函数,那么就称该类为抽象类。抽象类机制支持普通概念表示。抽象类只能用作其它类基类,抽象类不能建立对象。抽象类不能用作参数类型、函数返回类型或显式转换类型。但能够申明抽象类指针和引用。37第37页第七章虚函数和多态性7.2纯虚函数和抽象类纯虚函数和抽象类例子:classshape{public:

virtualvoidrotate(int)=0; virtualvoiddraw()=0;};…38第38页

用面向对象方法实现一个异质链表。异质是指链表中各表项内容类型不要求相同第39页(1)以大学环境为例,这里包含学生、职员和教师。希望对这些人信息进行管理(全部人员信息统计在一个链表中)。第40页学生:姓名、年纪、身份证号码、平均成绩。职员:姓名、年纪、身份证号码、小时工资。教师:姓名、年纪、身份证号码、年工资。第41页要求能实现三个操作:①插入。向异质链表中增加一个学生、职员或教师信息。②删除。从链表中删除一个学生、职员和教师信息。③打印。显示链表中全部信息。第42页(2)对于一些既是学生又是教师双重身份人,应能单独统计之。(3

温馨提示

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

评论

0/150

提交评论