《多态性和虚函数》PPT课件.ppt_第1页
《多态性和虚函数》PPT课件.ppt_第2页
《多态性和虚函数》PPT课件.ppt_第3页
《多态性和虚函数》PPT课件.ppt_第4页
《多态性和虚函数》PPT课件.ppt_第5页
已阅读5页,还剩86页未读 继续免费阅读

下载本文档

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

文档简介

多态性和虚函数,第05章,主要内容,5.2虚函数,5.4运算符重载,5.3纯虚函数和抽象类,5.1重载与覆盖,什么是多态性?,在C+中通过重载、覆盖、运算符重载、虚函数等技术,使得基类和派生类中可以出现同名的成员函数。不同的成员函数被调用时表现出不同的行为,表现出很强的灵活性,称为多态性。成员函数重载成员函数覆盖虚函数运算符重载,静态多态性和动态多态性,静态多态性:编译时的多态性,成员函数重载、覆盖、运算符重载都属于静态多态性。编译器根据实参数据类型或对象的数据类型,在编译时就确定调用哪个函数。动态多态性:运行时多态性,通过虚函数来实现。通过虚函数实现的动态多态性,在代码执行的过程中决定调用哪个函数。,1、成员函数重载和覆盖,重载:同一个类中,存在名称相同但“签名不同”的成员函数(函数参数类型或个数不同),编译时根据实参类型确定调用的是哪个版本的函数。覆盖:派生类和基类存在名称相同的成员函数,实现派生类方法覆盖(改造)基类方法的功能。如果要访问基类被覆盖方法,需要使用类名前缀。,2、成员函数重载,classInterintnum;public:Inter(inta)num=a;voidSetNum(inta)num=a;voidSetNum(doublea)num=int(a+0.5);voidshow()coutnumendl;,成员函数重载,voidmain()Interi(3);i.show();i.SetNum(5);i.show();i.SetNum(6.6);i.show();,运行结果357,3、覆盖技术,在派生类中定义与基类同名的成员函数后,会出现覆盖现象;实现重新定义基类成员函数。constdoublePI=3.14159;classPointdoublex,y;public:Point(doublei,doublej)x=i;y=j;doublearea()return0;;,覆盖技术,classCircle:publicPointdoubleradius;public:Circle(doublea,doubleb,doubler):Point(a,b)radius=r;doublearea()returnPI*radius*radius;;,覆盖技术,voidmain()Pointa(1.5,6.7);Circlec(1.5,6.7,2.5);coutarea()area(),调用的是Point的成员函数,输出0。,4、访问被覆盖的方法,classCPointintx,y;public:CPoint()x=0;y=0;CPoint(inta,intb)x=a;y=b;voidSet(inta,intb)x=a;y=b;voidShow()coutx“,”yendl;,访问被覆盖的方法,classCircle:publicCPointintradius;public:Circle(inta,intb,intr):CPoint(a,b)radius=r;voidSet(inta,intb,intr)CPoint:Set(a,b);radius=r;voidShow()coutradius“,”;CPoint:Show();,访问被覆盖的方法,voidmain()Circlec(3,4,5);c.Show();c.Set(5,6,7);c.Show();c.CPoint:Set(7,8);c.CPoint:Show();,间接调用基类成员函数,限定调用基类成员,不好!,运行结果5,3,47,5,67,8,主要内容,5.2虚函数,5.4运算符重载,5.3纯虚函数和抽象类,5.1重载与覆盖,1、为什么要运行时多态?,classMammalintage;doubleweight;public:Mammal(inta,doublew)age=a;weight=w;voidShout()cout“Imamammal.n”;,为什么要运行时多态?,classDog:publicMammalpublic:Dog(inta,doublew):Mammal(a,w)voidShout()cout“woo.n”;classCat:publicMammalpublic:Cat(inta,doublew):Mammal(a,w)voidShout()coutShout();voidmain()Mammalm(3,5);Dogdog(4,6);Catcat(4,7);Shout(,实际调用情况调用基类Shout调用基类Shout调用基类Shout,编译时就已经确定的事实,勉强的方法,voidmain()Mammalm(3,5);Dogdog(4,6);Catcat(4,7);m.Shout();dog.Shout();cat.Shout();,假设有100个不同类型的动物,代码要写100遍?!,2、解决之道:虚函数,classMammalintage;doubleweight;public:Mammal(inta,doublew)age=a;weight=w;virtualvoidShout()coutShout();voidmain()Mammal*p;if()p=newDog(3,4);elsep=newCat(5,6);Shout(p);deletep;,传过去什么对象,调用对应的Shout,静态联编无法实现,3、虚函数的说明,虚函数实现动态性关键在于使用基类指针,当用基类指针指向不同对象时,到底调用哪个版本成员函数,取决于所指向对象的类型。如果指向Dog类对象,则调用Dog类的Shout;如果指向Cat类对象,则调用Cat类的Shout;如果指向Mammal类对象,则调用基类的Shout。用虚函数实现的多态性是代码执行过程中的多态,大大增加了程序的灵活性。使用基类引用也可以实现动态多态性。,说明,在基类中定义虚函数后,往往在派生类中重新定义(确保返回类型和参数个数及类型完全匹配),才能形成动态多态性。在基类中定义的虚函数,在派生类中重定义后仍然为虚函数,即使不写virtual关键字。虚函数必须是类的公有或保护成员函数;友元函数和普通函数不能声明为虚函数;构造函数和静态成员函数不能被声明为虚函数;析构函数可以被声明为虚函数。,另一个示例,图形类基类:CShape派生类:CRect、CCircle、CTriangle应用的思路绘图程序中,设计一个链表,保存用户绘制的各种图形对象;刷新屏幕时,通过遍历链表,绘制所有对象。,基类的基本功能,classCShapepublic:voidDisplay();,派生类:CRect,classCRect:publicCShapeprivate:CPointp1,p2;public:voidDisplay();,派生类:CCircle,classCCircle:publicCShapeprivate:CPointcenter;intradius;public:voidDisplay();,派生类:CTriangle,classCTriangle:publicCShapeprivate:CPointp1,p2,p3;public:voidDisplay();,链表的遍历,voidReDraw(CShape*pHead)while(!pHead)pHead-Display();pHead=pHead-next;,问题:实际调用的都是基类的Display没有按预计的情况执行。,解决之道:虚函数,classCShapepublic:virtualvoidDisplay();,4、寻根求源:静态多态性,Mammal*p1,*p2;Dogdog(3,5);Catcat(5,7);p1=,5、寻根求源:虚函数,classApublic:inta;A(intx)a=x;virtualvoidShow()coutaendl;virtualvoidinc()a+;voidsub()a-;/非虚函数;,虚函数原理,classB:publicApublic:intb;B(intx,inty):A(x)b=y;voidShow()coutbendl;voidinc()b+;voidsub()b-;,虚函数原理,classC:publicApublic:intc;C(intx,inty):A(x)c=y;voidShow()coutcarea();voidmain()Circlec(3,4,5);coutCalArea(,X,主要内容,5.2虚函数,5.4运算符重载,5.3纯虚函数和抽象类,5.1重载与覆盖,classComplexdoublereal,imag;public:Complex()real=0;imag=0;Complex(doubler,doublei);Complex(constComplex,1、引入简单的复数类,Complex:Complex(doubler,doublei)real=r;imag=i;Complex:Complex(constComplex,复数类的实现,voidmain()Complexa(3,4),b(4,5);a.print();a.copy(b);a.print();,复数类的应用,输出结果3+4i4+5i,仅有的成员函数还远远不够,加法、减法?,classComplexdoublereal,imag;public:Complex()real=0;imag=0;Complex(doubler,doublei);Complex(constComplex,2、实现复数相加,ComplexComplex:Add(constComplex,实现复数相加,创建并返回临时对象,voidmain()Complexa(3,4),b(4,5),c(0,0);a.print();a.copy(b);a.print();c=a.Add(b);c.print();,复数类的应用,输出结果3+4i4+5i7+9i,不直观,为什么不是a+b?,从简单数据类型开始思考运算符的实质?表达式9/2=4,而9.0/2.0=4.5。这里的同一个运算符“/”,由于所操作的数据不同而具有不同的意义,为什么?如何实现的?C+是由函数组成的,在C+内部,任何运算都是通过函数来实现的。在处理表达式8+7时,C+将这个表达式解释成如下的函数调用表达式:operator+(8,7);相同的运算符对不同数据有不同的操作,实质上是函数的重载!,3、引入运算符重载的概念,C+已经为各种基本数据类型定义了可能的运算符函数,如operator+(int,int)operator-(int,int)operator/(int,int);operator/(double,double);如果想让类的对象也能使用这些运算符,就需要重载对应的运算符。可以使用友元函数和成员函数两种方法实现运算符重载。,引入运算符重载的概念,classComplexdoublereal,imag;public:Complex()real=0;imag=0;Complex(doubler,doublei);Complex(constComplex,4、成员函数重载+,相当于函数名,ComplexComplex:operator+(constComplex,成员函数重载+,更自然、更简洁c=a.operator+(b);,输出结果8+10i,Complex,5、成员函数重载+:小问题,构造临时对象,返回后释放,避免使用引用,classComplexdoublereal,imag;public:Complex()real=0;imag=0;Complex(doubler,doublei);Complex(constComplex,6、友元函数重载-,相当于函数名,Complexoperator-(Complexa,Complexb)returnComplex(a.real+b.real,a.imag+b.imag);voidmain()Complexa(3,4),b(5,6),c;c=a-b;c.print();,友元函数重载-,输出结果-2-2i,classComplexdoublereal,imag;public:Complex()real=0;imag=0;Complex(doubler,doublei);Complex(constComplex,7、重载赋值运算符:成员函数,voidComplex:operator=(constComplex,重载赋值运算符:成员函数,输出结果3+4i,voidComplex:operator=(constComplex,重载赋值运算符:问题,出现语法错误,=运算符右结合先执行b=a返回值为void无法赋给a,X,classComplexComplexoperator=(constComplex,重载赋值运算符:问题的解决,效率太低,classComplexComplex,重载赋值运算符:问题的解决,c=b=a;先执行b=a,b被赋值后,返回b的引用,在赋值给c,最后的返回值丢弃,classComplexdoublereal,imag;public:Complex()real=0;imag=0;Complex(doubler);/类型转换构造函数Complex(doubler,doublei);Complex(constComplex,8、复数与实数运算:类型转换,Complex:Complex(doubler)real=r;imag=0;voidmain()Complexa(3,4),b,c;b=a+2;b.print();/c=2+a;,复数与实数运算:类型转换,先将2转换为Complex对象;将转换后的对象与a相加结果赋给b,X,a不能转换为整数,classComplexdoublereal,imag;public:Complex()real=0;imag=0;Complex(doubler);/类型转换构造函数Complex(doubler,doublei);Complex(constComplex,9、复数与实数运算:使用友元,Complex:Complex(doubler)real=r;imag=0;Complexoperator+(Complex,复数与实数运算:最好使用友元,voidmain()Complexa(3,4),b,c;b=a+2;b.print();c=2+a;c.print();,复数与实数运算,输出结果5+4i5+4i,classStringchar*str;public:String()str=NULL;String(char*p)str=newcharstrlen(p)+1;strcpy(str,p);voidshow()coutstrendl;,10、字符串类:浅拷贝,voidmain()Stringstr1(“Hello”);Stringstr2(“World”);str1=str2;,字符串类:浅拷贝,编程迷失的不可访问的内存!,classStringchar*str;public:String()deletestr;String()str=NULL;String(char*p);String(String,字符串类:深拷贝,String:String(char*p)str=newcharstrlen(p)+1;strcpy(str,p);String:String(String,字符串类:深拷贝,String:String(charc)str=newchar2;str0=c;str1=0;Stringoperator+(String,字符串类:深拷贝,String,字符串类:深拷贝,voidmain()Strings1(“Hello”);Strings2(“World”);Strings3;s3=s1

温馨提示

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

评论

0/150

提交评论