多态性和虚函数.ppt

上传人:小飞机 文档编号:6224048 上传时间:2023-10-07 格式:PPT 页数:91 大小:666.50KB
返回 下载 相关 举报
多态性和虚函数.ppt_第1页
第1页 / 共91页
多态性和虚函数.ppt_第2页
第2页 / 共91页
多态性和虚函数.ppt_第3页
第3页 / 共91页
多态性和虚函数.ppt_第4页
第4页 / 共91页
多态性和虚函数.ppt_第5页
第5页 / 共91页
点击查看更多>>
资源描述

《多态性和虚函数.ppt》由会员分享,可在线阅读,更多相关《多态性和虚函数.ppt(91页珍藏版)》请在三一办公上搜索。

1、多态性和虚函数,第05章,主要内容,5.2 虚函数,5.4 运算符重载,5.3 纯虚函数和抽象类,5.1 重载与覆盖,什么是多态性?,在C+中通过重载、覆盖、运算符重载、虚函数等技术,使得基类和派生类中可以出现同名的成员函数。不同的成员函数被调用时表现出不同的行为,表现出很强的灵活性,称为多态性。成员函数重载成员函数覆盖虚函数运算符重载,静态多态性和动态多态性,静态多态性:编译时的多态性,成员函数重载、覆盖、运算符重载都属于静态多态性。编译器根据实参数据类型或对象的数据类型,在编译时就确定调用哪个函数。动态多态性:运行时多态性,通过虚函数来实现。通过虚函数实现的动态多态性,在代码执行的过程中决

2、定调用哪个函数。,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 m

3、ain()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

4、 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的数据类型是P

5、oint,根据赋值兼容性规则,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,

6、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

7、 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

8、-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

9、 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

10、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、虚函数的说明,虚函数实现动态性关键在于使用基类指针,当用基类指针指向不

11、同对象时,到底调用哪个版本成员函数,取决于所指向对象的类型。如果指向Dog类对象,则调用Dog类的Shout;如果指向Cat类对象,则调用Cat类的Shout;如果指向Mammal类对象,则调用基类的Shout。用虚函数实现的多态性是代码执行过程中的多态,大大增加了程序的灵活性。使用基类引用也可以实现动态多态性。,说明,在基类中定义虚函数后,往往在派生类中重新定义(确保返回类型和参数个数及类型完全匹配),才能形成动态多态性。在基类中定义的虚函数,在派生类中重定义后仍然为虚函数,即使不写virtual关键字。虚函数必须是类的公有或保护成员函数;友元函数和普通函数不能声明为虚函数;构造函数和静态成

12、员函数不能被声明为虚函数;析构函数可以被声明为虚函数。,另一个示例,图形类基类:CShape派生类:CRect、CCircle、CTriangle应用的思路绘图程序中,设计一个链表,保存用户绘制的各种图形对象;刷新屏幕时,通过遍历链表,绘制所有对象。,基类的基本功能,class CShapepublic:void Display();,派生类:CRect,class CRect:public CShapeprivate:CPoint p1,p2;public:void Display();,派生类:CCircle,class CCircle:public CShapeprivate:CPoin

13、t 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、寻根求

14、源:静态多态性,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:

15、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 Shaped

16、ouble 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;,由于静态联

17、编,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;,纯虚函数只有定义

18、没有实现!,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

19、;width=w;double area()return width*length;,派生类,double CalArea(Shape,输出结果Circle area:78.5398Rectangle area:30,3、抽象类,凡是含有纯虚函数的类称为抽象类。抽象类往往描述的是一般抽象概念,如形状类、动物类,其中的纯虚函数如area没有实际意义,不能提供实现代码。要求派生类如Circle类提供自己版本的area实现。C+规定,不能在内存中创建抽象类对象,无论是定义抽象类对象、作为形参或返回值,还是动态创建抽象类对象都是非法的。但可以定义一个抽象类指针(引用),并用该指针指向不同的派生类对象,

20、以实现多态性。,抽象类,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;

21、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,

22、实现复数相加,创建并返回临时对象,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+将这个表达式解释成如下的函数调用表达式:opera

23、tor+(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

24、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、友元函数重载-,相当于函数

25、名,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=

26、(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:Co

27、mplex()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;publi

28、c: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

29、;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,字符串类:深

30、拷贝,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();,字符串类:深拷贝,输出结果He

31、lloHelloWorld,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,成员函数实现+

32、,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,因为返回值可能 作为左值使用!,

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 生活休闲 > 在线阅读


备案号:宁ICP备20000045号-2

经营许可证:宁B2-20210002

宁公网安备 64010402000987号