欢迎来到课桌文档! | 帮助中心 课桌文档-建筑工程资料库
课桌文档
全部分类
  • 党建之窗>
  • 感悟体会>
  • 百家争鸣>
  • 教育整顿>
  • 文笔提升>
  • 热门分类>
  • 计划总结>
  • 致辞演讲>
  • 在线阅读>
  • ImageVerifierCode 换一换
    首页 课桌文档 > 资源分类 > PPT文档下载  

    第05章多态性和虚函数.ppt

    • 资源ID:675590       资源大小:1.39MB        全文页数:91页
    • 资源格式: PPT        下载积分:10金币
    快捷下载 游客一键下载
    会员登录下载
    三方登录下载: 微信开放平台登录 QQ登录  
    下载资源需要10金币
    邮箱/手机:
    温馨提示:
    用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)
    支付方式: 支付宝    微信支付   
    验证码:   换一换

    加入VIP免费专享
     
    账号:
    密码:
    验证码:   换一换
      忘记密码?
        
    友情提示
    2、PDF文件下载后,可能会被浏览器默认打开,此种情况可以点击浏览器菜单,保存网页到桌面,就可以正常下载了。
    3、本站不支持迅雷下载,请使用电脑自带的IE浏览器,或者360浏览器、谷歌浏览器下载即可。
    4、本站资源下载后的文档和图纸-无水印,预览文档经过压缩,下载后原文更清晰。
    5、试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。

    第05章多态性和虚函数.ppt

    多态性和虚函数,第05章,主要内容,5.2 虚函数,5.4 运算符重载,5.3 纯虚函数和抽象类,5.1 重载与覆盖,什么是多态性?,在C+中通过重载、覆盖、运算符重载、虚函数等技术,使得基类和派生类中可以出现同名的成员函数。不同的成员函数被调用时表现出不同的行为,表现出很强的灵活性,称为多态性。成员函数重载成员函数覆盖虚函数运算符重载,静态多态性和动态多态性,静态多态性:编译时的多态性,成员函数重载、覆盖、运算符重载都属于静态多态性。编译器根据实参数据类型或对象的数据类型,在编译时就确定调用哪个函数。动态多态性:运行时多态性,通过虚函数来实现。通过虚函数实现的动态多态性,在代码执行的过程中决定调用哪个函数。,1、成员函数重载和覆盖,重载:同一个类中,存在名称相同但“签名不同”的成员函数(函数参数类型或个数不同),编译时根据实参类型确定调用的是哪个版本的函数。覆盖:派生类和基类存在名称相同的成员函数,实现派生类方法覆盖(改造)基类方法的功能。如果要访问基类被覆盖方法,需要使用类名前缀。,2、成员函数重载,class Interint num;public:Inter(int a)num=a;void SetNum(int a)num=a;void SetNum(double a)num=int(a+0.5);void show()coutnumendl;,成员函数重载,void main()Inter i(3);i.show();i.SetNum(5);i.show();i.SetNum(6.6);i.show();,运行结果357,3、覆盖技术,在派生类中定义与基类同名的成员函数后,会出现覆盖现象;实现重新定义基类成员函数。const double PI=3.14159;class Point double x,y;public:Point(double i,double j)x=i;y=j;double area()return 0;;,覆盖技术,class Circle:public Point double radius;public:Circle(double a,double b,double r):Point(a,b)radius=r;double area()return PI*radius*radius;;,覆盖技术,void main()Point a(1.5,6.7);Circle c(1.5,6.7,2.5);coutarea()endl;,运行结果area of a:0area of c:19.6349area of c:0,覆盖技术,a.area()表达式明确告诉编译器,它调用的是Point的成员函数area,输出0。c.area()表达式明确表示调用的是Circle的成员函数area,输出19.6349。因为指针p的数据类型是Point,根据赋值兼容性规则,p-area(),调用的是Point的成员函数,输出0。,4、访问被覆盖的方法,class CPointint x,y;public:CPoint()x=0;y=0;CPoint(int a,int b)x=a;y=b;void Set(int a,int b)x=a;y=b;void Show()coutx“,”yendl;,访问被覆盖的方法,class Circle:public CPointint radius;public:Circle(int a,int b,int r):CPoint(a,b)radius=r;void Set(int a,int b,int r)CPoint:Set(a,b);radius=r;void Show()coutradius“,”;CPoint:Show();,访问被覆盖的方法,void main()Circle c(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、为什么要运行时多态?,class Mammalint age;double weight;public:Mammal(int a,double w)age=a;weight=w;void Shout()cout“Im a mammal.n”;,为什么要运行时多态?,class Dog:public Mammalpublic:Dog(int a,double w):Mammal(a,w)void Shout()cout“woo.n”;class Cat:public Mammalpublic:Cat(int a,double w):Mammal(a,w)void Shout()cout“meow.n”;,为什么要运行时多态?,void Shout(Mammal*p)p-Shout();void main()Mammal m(3,5);Dog dog(4,6);Cat cat(4,7);Shout(,用户的期望调用基类Shout调用Dog类Shout调用Cat类Shout,?,输出结果Im a mammal.Im a mammal.Im a mammal.,编译器无能为力!,void Shout(Mammal*p)p-Shout();void main()Mammal m(3,5);Dog dog(4,6);Cat cat(4,7);Shout(,实际调用情况调用基类Shout调用基类Shout调用基类Shout,编译时就已经确定的事实,勉强的方法,void main()Mammal m(3,5);Dog dog(4,6);Cat cat(4,7);m.Shout();dog.Shout();cat.Shout();,假设有100个不同类型的动物,代码要写100遍?!,2、解决之道:虚函数,class Mammalint age;double weight;public:Mammal(int a,double w)age=a;weight=w;virtual void Shout()cout“Im a mammal.n”;,私有函数不行,神奇的变化,/Dog类和Cat类保持不变void Shout(Mammal*p)p-Shout();void main()Mammal m(3,5);Dog dog(4,6);Cat cat(4,7);Shout(,实际调用情况调用基类Shout调用Dog类Shout调用Cat类Shout,输出结果Im a mammal.woo.meow.,一个接口,多种方法,void Shout(Mammal*p)p-Shout();void main()Mammal*p;if()p=new Dog(3,4);else p=new Cat(5,6);Shout(p);delete p;,传过去什么对象,调用对应的Shout,静态联编无法实现,3、虚函数的说明,虚函数实现动态性关键在于使用基类指针,当用基类指针指向不同对象时,到底调用哪个版本成员函数,取决于所指向对象的类型。如果指向Dog类对象,则调用Dog类的Shout;如果指向Cat类对象,则调用Cat类的Shout;如果指向Mammal类对象,则调用基类的Shout。用虚函数实现的多态性是代码执行过程中的多态,大大增加了程序的灵活性。使用基类引用也可以实现动态多态性。,说明,在基类中定义虚函数后,往往在派生类中重新定义(确保返回类型和参数个数及类型完全匹配),才能形成动态多态性。在基类中定义的虚函数,在派生类中重定义后仍然为虚函数,即使不写virtual关键字。虚函数必须是类的公有或保护成员函数;友元函数和普通函数不能声明为虚函数;构造函数和静态成员函数不能被声明为虚函数;析构函数可以被声明为虚函数。,另一个示例,图形类基类:CShape派生类:CRect、CCircle、CTriangle应用的思路绘图程序中,设计一个链表,保存用户绘制的各种图形对象;刷新屏幕时,通过遍历链表,绘制所有对象。,基类的基本功能,class CShapepublic:void Display();,派生类:CRect,class CRect:public CShapeprivate:CPoint p1,p2;public:void Display();,派生类:CCircle,class CCircle:public CShapeprivate:CPoint center;int radius;public:void Display();,派生类:CTriangle,class CTriangle:public CShapeprivate:CPoint p1,p2,p3;public:void Display();,链表的遍历,void ReDraw(CShape*pHead)while(!pHead)pHead-Display();pHead=pHead-next;,问题:实际调用的都是基类的Display没有按预计的情况执行。,解决之道:虚函数,class CShapepublic:virtual void Display();,4、寻根求源:静态多态性,Mammal*p1,*p2;Dog dog(3,5);Cat cat(5,7);p1=,5、寻根求源:虚函数,class Apublic:int a;A(int x)a=x;virtual void Show()coutaendl;virtual void inc()a+;void sub()a-;/非虚函数;,虚函数原理,class B:public Apublic:int b;B(int x,int y):A(x)b=y;void Show()coutbendl;void inc()b+;void sub()b-;,虚函数原理,class C:public Apublic:int c;C(int x,int y):A(x)c=y;void Show()coutcendl;void inc()c+;void sub()c-;,虚函数原理,void main()A aa(3);B bb(4,5);C cc(6,7);,虚函数原理:基类对象,void main()A aa(3);A*p=,虚函数原理:派生类对象,void main()B bb(4,5);A*p=,虚函数原理:派生类对象,void main()C cc(6,7);A*p=,6、虚析构函数,C+中规定,某个类中含有虚函数,则应该将其析构函数设置为虚函数。否则容易出现内存泄漏等问题。class Shapedouble x,y;public:virtual Shape()virtual double area()return 0;,派生类,const double PI=3.1415926;class Circle:public Shapedouble radius;public:Circle(double x,double y,double z):Shape(x,y)radius=z;double area()return PI*radius*radius;Circle();,虚析构函数:原因,如果不采用虚析构函数Shape*p=new Circle(3,5,2);delete p;,由于静态联编,Circle类析构函数被跳过去,虚析构函数:原因,如果使用虚析构函数Shape*p=new Circle(3,5,2);delete p;,动态联编,调用Circle类析构函数,主要内容,5.2 虚函数,5.4 运算符重载,5.3 纯虚函数和抽象类,5.1 重载与覆盖,1、定义纯虚函数,纯虚函数是一种特殊的虚函数,在基类中声明为虚函数,但不提供实现部分,而要求各派生类提供该虚函数的不同版本实现。class Shapedouble x,y;/基点坐标public:Shape(double a,double b)x=a;y=b;virtual double area()=0;,纯虚函数只有定义没有实现!,2、派生类,const double PI=3.1415926;class Circle:public Shapedouble radius;public:Circle(double x,double y,double z):Shape(x,y)radius=z;double area()return PI*radius*radius;,派生类,class Rectangle:public Shapedouble length,width;public:Rectangle(double x,double y,double z,double w):Shape(x,y)length=z;width=w;double area()return width*length;,派生类,double CalArea(Shape,输出结果Circle area:78.5398Rectangle area:30,3、抽象类,凡是含有纯虚函数的类称为抽象类。抽象类往往描述的是一般抽象概念,如形状类、动物类,其中的纯虚函数如area没有实际意义,不能提供实现代码。要求派生类如Circle类提供自己版本的area实现。C+规定,不能在内存中创建抽象类对象,无论是定义抽象类对象、作为形参或返回值,还是动态创建抽象类对象都是非法的。但可以定义一个抽象类指针(引用),并用该指针指向不同的派生类对象,以实现多态性。,抽象类,double CalArea(Shape*p)return p-area();void main()Circle c(3,4,5);coutCalArea(,X,主要内容,5.2 虚函数,5.4 运算符重载,5.3 纯虚函数和抽象类,5.1 重载与覆盖,class Complexdouble real,imag;public:Complex()real=0;imag=0;Complex(double r,double i);Complex(const Complex,1、引入简单的复数类,Complex:Complex(double r,double i)real=r;imag=i;Complex:Complex(const Complex,复数类的实现,void main()Complex a(3,4),b(4,5);a.print();a.copy(b);a.print();,复数类的应用,输出结果3+4i4+5i,仅有的成员函数还远远不够,加法、减法?,class Complexdouble real,imag;public:Complex()real=0;imag=0;Complex(double r,double i);Complex(const Complex,2、实现复数相加,Complex Complex:Add(const Complex,实现复数相加,创建并返回临时对象,void main()Complex a(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);如果想让类的对象也能使用这些运算符,就需要重载对应的运算符。可以使用友元函数和成员函数两种方法实现运算符重载。,引入运算符重载的概念,class Complexdouble real,imag;public:Complex()real=0;imag=0;Complex(double r,double i);Complex(const Complex,4、成员函数重载+,相当于函数名,Complex Complex:operator+(const Complex,成员函数重载+,更自然、更简洁c=a.operator+(b);,输出结果8+10i,Complex,5、成员函数重载+:小问题,构造临时对象,返回后释放,避免使用引用,class Complexdouble real,imag;public:Complex()real=0;imag=0;Complex(double r,double i);Complex(const Complex,6、友元函数重载-,相当于函数名,Complex operator-(Complex a,Complex b)return Complex(a.real+b.real,a.imag+b.imag);void main()Complex a(3,4),b(5,6),c;c=a-b;c.print();,友元函数重载-,输出结果-2-2i,class Complexdouble real,imag;public:Complex()real=0;imag=0;Complex(double r,double i);Complex(const Complex,7、重载赋值运算符:成员函数,void Complex:operator=(const Complex,重载赋值运算符:成员函数,输出结果3+4i,void Complex:operator=(const Complex,重载赋值运算符:问题,出现语法错误,=运算符右结合先执行b=a返回值为void无法赋给a,X,class ComplexComplex operator=(const Complex,重载赋值运算符:问题的解决,效率太低,class ComplexComplex,重载赋值运算符:问题的解决,c=b=a;先执行b=a,b被赋值后,返回b的引用,在赋值给c,最后的返回值丢弃,class Complexdouble real,imag;public:Complex()real=0;imag=0;Complex(double r);/类型转换构造函数Complex(double r,double i);Complex(const Complex,8、复数与实数运算:类型转换,Complex:Complex(double r)real=r;imag=0;void main()Complex a(3,4),b,c;b=a+2;b.print();/c=2+a;,复数与实数运算:类型转换,先将2转换为 Complex对象;将转换后的对象 与a相加 结果赋给b,X,a不能转换为整数,class Complexdouble real,imag;public:Complex()real=0;imag=0;Complex(double r);/类型转换构造函数Complex(double r,double i);Complex(const Complex,9、复数与实数运算:使用友元,Complex:Complex(double r)real=r;imag=0;Complex operator+(Complex,复数与实数运算:最好使用友元,void main()Complex a(3,4),b,c;b=a+2;b.print();c=2+a;c.print();,复数与实数运算,输出结果5+4i5+4i,class Stringchar*str;public:String()str=NULL;String(char*p)str=new charstrlen(p)+1;strcpy(str,p);void show()coutstrendl;,10、字符串类:浅拷贝,void main()String str1(“Hello”);String str2(“World”);str1=str2;,字符串类:浅拷贝,编程迷失的不可 访问的内存!,class Stringchar*str;public:String()delete str;String()str=NULL;String(char*p);String(String,字符串类:深拷贝,String:String(char*p)str=new charstrlen(p)+1;strcpy(str,p);String:String(String,字符串类:深拷贝,String:String(char c)str=new char2;str0=c;str1=0;String operator+(String,字符串类:深拷贝,String,字符串类:深拷贝,void main()String s1(“Hello”);String s2(“World”);String s3;s3=s1;s3.show();s3=s1+s2;s3.show();,字符串类:深拷贝,输出结果HelloHelloWorld,11、前置、后置+,+和-运算符也可以重载,但为了区分前置和后置之分。C+约定把前置运算符重载为单目运算符函数,即表达式+a;解释为a.operator+()把后置运算符看成双目运算符,在参数表内放置一个整型参数,该参数没有任何作用,只是用来区分前置和后置。a+;解释为a.operator+(int),成员函数实现+,class Counterint count;public:Counter()count=0;Counter(int a)count=a;void print()coutcountendl;Counter,成员函数实现+,Counter,成员函数实现+,void main()Counter c(3);(c+).print();(+c).print();,输出结果35,友元函数实现+,class Counterint count;public:Counter()count=0;Counter(int a)count=a;void print()coutcountendl;friend Counter,友元函数实现+,Counter,友元函数实现+,void main()Counter c(3);(c+).print();(+c).print();,输出结果35,12、重载下标运算符,class Stringchar*str;public:String()delete str;String()str=NULL;String(char*p);String(String,重载下标运算符,char,输出结果ehollo,因为返回值可能 作为左值使用!,

    注意事项

    本文(第05章多态性和虚函数.ppt)为本站会员(夺命阿水)主动上传,课桌文档仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知课桌文档(点击联系客服),我们立即给予删除!

    温馨提示:如果因为网速或其他原因下载失败请重新下载,重复下载不扣分。




    备案号:宁ICP备20000045号-1

    经营许可证:宁B2-20210002

    宁公网安备 64010402000986号

    课桌文档
    收起
    展开