《面向对象课件第八章优秀PPT.ppt》由会员分享,可在线阅读,更多相关《面向对象课件第八章优秀PPT.ppt(94页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、面向对象课件第八章第一页,本课件共有94页第八章第八章 多态性多态性8.1 8.1 多态性的基本概念多态性的基本概念8.2 8.2 函数重载函数重载8.3 8.3 拷贝构造函数拷贝构造函数8.4 8.4 运算符重载运算符重载8.5 8.5 虚函数虚函数8.6 8.6 纯虚函数与抽象类纯虚函数与抽象类 第二页,本课件共有94页8.1 8.1 多态性的基本概念多态性的基本概念w在基类中定义的属性或操作被派生类继承之后,可以具有不同的数据类型或表现出不同的行为,从而同一个属性或操作名称在各个派生类中具有不同的含义ManagerWifeAssistantSecretary第三页,本课件共有94页8.1
2、 8.1 多态性的基本概念多态性的基本概念C+语言支持两种多态性语言支持两种多态性w编译时的多态性通过重载实现(函数重载,运算符重载)w运行时的多态性通过虚函数实现(借助抽象类和动态绑定)第四页,本课件共有94页8.1 8.1 多态性的基本概念多态性的基本概念w绑定绑定将一个函数调用链接上相应的函数体代码的过程w静态绑定静态绑定在编译时就能够确定调用哪一个函数w动态绑定动态绑定在运行时才能够确定调用哪一个函数第五页,本课件共有94页8.1 8.1 多态性的基本概念多态性的基本概念w本章重点本章重点重载重载:函数重载,运算符重载 静态绑定静态绑定虚函数:虚函数:抽象类动态绑定动态绑定第六页,本课
3、件共有94页8.2 8.2 函数重载函数重载w函数重载(函数名相同,函数参数不同)void print(char);void print(int,int);void print(float);void print(char*);w函数调用print(“Hello,overload!”);print(3,5);第七页,本课件共有94页8.2 8.2 函数重载函数重载w类构造函数的重载类构造函数的重载class Apublic:A();A(int);A(char c);/;A aa(34);第八页,本课件共有94页8.2 8.2 函数重载函数重载函数重载的注意事项函数重载的注意事项 参数不同,是指
4、参数的个数,参数的类型不同 只有返回值类型不同,不是函数重载 不要用重载函数描述毫不相干的函数 在重载函数中使用缺省参数时应注意二义性问题第九页,本课件共有94页8.2 8.2 函数重载函数重载例:void print(int a,int b)void print(int a,int b,int c)函数说明:void print(int a,int b,int c=50);函数调用:print(10,100);/error!系统不知调用哪个函数第十页,本课件共有94页8.2 8.2 函数重载函数重载例:参数类型不同例:参数类型不同float abs(float x)double abs(do
5、uble x)函数调用:函数调用:abs(5);/error!因为系统不知应将5转换成float,还是double 第十一页,本课件共有94页8.2 8.2 函数重载函数重载在函数调用时,如找不到与实参完全匹配的函数原型,C+的隐式类型转换如能将一个类型转为能与函数原型匹配,则选择调用该重载函数例:函数原型:int func(double d);函数调用:func(A);/系统自动将A(字符型)转换成double第十二页,本课件共有94页8.3 8.3 拷贝构造函数拷贝构造函数构造对象的两个特殊构造函数1.默认构造函数(复习)2.拷贝构造函数第十三页,本课件共有94页8.3 8.3 拷贝构造函
6、数拷贝构造函数w默认构造函数默认构造函数例:A aa;/当定义一个对象而不给它任何初始值时,系统就要调用默认构造函数w默认构造函数:默认构造函数:参数表为空或所有参数都有默认值的构造函数如:A();或 A(int i=0,int j=5);第十四页,本课件共有94页8.3 8.3 拷贝构造函数拷贝构造函数遇下列情况系统自动调用默认构造函数来构造对象遇下列情况系统自动调用默认构造函数来构造对象 直接定义一个对象而没有给初始值例:A aa;用new动态申请的对象而没有给初始值例:A *pa=new A;或:A *pa;pa=new A;定义了一个对象数组例:A array10;第十五页,本课件共有
7、94页8.3 8.3 拷贝构造函数拷贝构造函数w默认构造函数的作用为了让所定义的类能够被使用(有时甚至没有给对象任何初始化信息)w当所定义的类没有提供任何构造函数时,系统将为类自动生成一个默认构造函数第十六页,本课件共有94页8.3 8.3 拷贝构造函数拷贝构造函数只要定义了一个构造函数,系统将不再生成默认构造函数例:class AA(int i);如下定义类A的对象:A aa;A array10;A *pa=new A;w一般情况下,都要定义自己的构造函数,并至少定义一个默认构造函数第十七页,本课件共有94页8.3 8.3 拷贝构造函数拷贝构造函数拷贝构造函数的作用拷贝构造函数的作用w用一个
8、对象去构造另一个同类的对象用一个对象去构造另一个同类的对象例:STUDENT s1(“Jenny”);/系统调用构造函数STUDENT s2=s1;/系统调用拷贝构造函数,用对 象s1的值去初始化对象s2w对象作为函数参数对象作为函数参数w对象作为函数返回值对象作为函数返回值第十八页,本课件共有94页8.3 8.3 拷贝构造函数拷贝构造函数w拷贝构造函数的形式拷贝构造函数的形式(STUDENT类)STUDENT(const STUDENT&obj);用obj初始化一个新对象第十九页,本课件共有94页8.3 8.3 拷贝构造函数拷贝构造函数拷贝构造函数的拷贝构造函数的说明:说明:拷贝构造函数只有
9、一个参数,用同一类的对象作参数 参数传递方式必须按引用调用函数 每个类都必须有一个拷贝构造函数,如果没定义,系 统自动生成一个缺省的拷贝构造函数缺省拷贝构造函数的含义:缺省拷贝构造函数的含义:用一个已知对象的数据成员的值拷贝给正在创建的另一个同类的对象 第二十页,本课件共有94页8.3 8.3 拷贝构造函数拷贝构造函数w拷贝构造函数在下列情况被系统自动调用:拷贝构造函数在下列情况被系统自动调用:当一个对象以声明初始化的方式复制时 如:STUDENT s2=s1;当一个对象作为参数传递给一个函数时 例:void main()STUDENT ms;func(ms);void func(STUDEN
10、T fs)/调用拷贝构造函数将实参 ms对象的副本拷贝给fs/func()函数调用结束 返回时,还要析构fs第二十一页,本课件共有94页8.3 8.3 拷贝构造函数拷贝构造函数 当一个对象作为值从一个函数返回时例:STUDENT func()STUDENT ms(“Randy”);return ms;void main()STUDENT s;s=func();函数func的栈区main函数的栈区mss临时对象放入取出/系统调用拷贝构造函数,将ms 拷贝到新创建的临时对象中第二十二页,本课件共有94页例:分析程序执行结果(拷贝构造函数举例)class STUDENTpublic:STUDENT(
11、char*pn=“no name”,int sid=0)id=sid;strcpy(name,pn);cout“constructing new student”nameendl;STUDENT(const STUDENT&s)/拷贝构造函数cout“constructing copy of”s.nameendl;strcpy(name,“copy of”);strcat(name,s.name);id=s.id;STUDENT()cout“Destructing”nameendl;protected:char name40;int id;第二十三页,本课件共有94页void fn(STUDE
12、NT s)cout“In function fn()n”;void main()STUDENT randy(“Randy”,1234);cout“calling fn()n”;fn(randy);cout“Returned from fn()n”;第二十四页,本课件共有94页程序执行结果:constructing new student Randy/调用普通构造函数calling fn()/main()函数中的输出constructing copy of Randy/调用拷贝构造函数In function fn()/fn()函数中的输出Destructing copy of Randy /从f
13、n函数返回时,形参s被析构Returned from fn()/回到main函数后的输出Destructing Randy /main函数执行结束时,对象randy被析构第二十五页,本课件共有94页8.3 8.3 拷贝构造函数拷贝构造函数浅拷贝与深拷贝浅拷贝与深拷贝(shallow copy 与 deep copy)w浅拷贝(见下图)pName堆p1pNamepName堆p1p2浅拷贝:创建p2时,对象p1被复制给了p2,但资源并 未复制,p1,p2指向同一资源默认拷贝构造函数是浅拷贝(浅拷贝是不安全的)拷贝前拷贝后第二十六页,本课件共有94页8.3 8.3 拷贝构造函数拷贝构造函数w深拷贝(
14、见下图)pName堆p1pNamepName堆p1p2堆拷贝前拷贝后深拷贝:对象p1被复制给p2时,不但拷贝成员,也拷贝资源自己定义拷贝构造函数,在函数体中用new动态申请内存,以实现深拷贝第二十七页,本课件共有94页8.4 8.4 运算符重载运算符重载运算符重载的概念友元的概念成员函数与友元函数 小 结第二十八页,本课件共有94页8.4 8.4 运算符重载运算符重载w运算符重载的含义对对C+C+预定义的运算符功能的扩展预定义的运算符功能的扩展例:QUEUE q1,q2;q1=q1+q2;MATRIX m1,m2,m;m=m1*m2;COUNTER c;c+;对象作操作数对象作操作数第二十九页
15、,本课件共有94页8.4 8.4 运算符重载运算符重载w运算符重载的目的增加程序的可读性,简洁,直接,易理解增加程序的可读性,简洁,直接,易理解例:q1.addqueue(q2);q1=q1+q2;m=multimatrix(m1,m2);m=m1*m2;IncCounter(c);c+;看起来简单与数学公式相似成员函数可以用成员函数来实现运算符重载第三十页,本课件共有94页8.4 8.4 运算符重载运算符重载w可以重载的运算符可以重载的运算符几乎所有的C+预定义的运算符都可以被重载(都可以为自己定义的类重载,即用对象作为这 些运算符 的操作数参与运算)w不可以重载的运算符不可以重载的运算符圆
16、点运算符 .域运算符 :间接访问运算符 *指针成员运算符 条件运算符?:第三十一页,本课件共有94页8.4 8.4 运算符重载运算符重载w重载运算符的定义返回类型返回类型 operator 运算符运算符(参数表参数表)例:要重载运算符“+”返回类型 operator +(类型1 参数1,类型2 参数2)例:要重载运算符“+”返回类型 operator +(类型 参数)可以改变可以改变但参数个数不能变是运算符不是函数第三十二页,本课件共有94页8.4 8.4 运算符重载运算符重载运算符重载时应遵守的规则运算符重载时应遵守的规则w重载的运算符至少有一个参数的类型与自定义的类有关(即重载的运算符的参
17、数不能都是预定义的数据类型)w重载时,运算符的优先级、结合性以及参数的个数不能改变w不能创造新的运算符第三十三页,本课件共有94页8.4 8.4 运算符重载运算符重载w友元的概念友元的概念可以访问类的保护、私有成员的函数或类w如果一个函数与某个类关系密切,可以定义其为友元函数w如果一个类与某个类关系密切,可以定义其为友元类第三十四页,本课件共有94页8.4 8.4 运算符重载运算符重载w使用友元的目的使用友元的目的提高程序的运行效率 类的数据成员大部分为私有成员,只能通过成员函数去访问,当对某些成员函数需多次调用时,会影响程序的运行效率第三十五页,本课件共有94页8.4 8.4 运算符重载运算
18、符重载w友元的定义(声明)友元的定义(声明)友元是一种定义在类外部的普通函数或类,但它需要在类体内进行声明第三十六页,本课件共有94页8.4 8.4 运算符重载运算符重载w声明一个函数声明一个函数f()是另一个类是另一个类B的友元函数的方式的友元函数的方式class Bfriend 函数f()的原型;/其它类成员的定义或声明;w声明一个类声明一个类A是另一个类是另一个类B的友元类的方式的友元类的方式class Bfriend class A;/其它类成员的定义或声明;第三十七页,本课件共有94页8.4 8.4 运算符重载运算符重载w当将一个函数f()或一个类A声明为另一个类B的友元后,f()或
19、类A就可以直接访问类B的任何成员,包括私有和保护成员w友元函数f()与友元类A的定义、调用等与普通函数、普通类完全一样第三十八页,本课件共有94页8.4 8.4 运算符重载运算符重载友元通常应用在下列情况友元通常应用在下列情况w一个函数需要经常且大量的访问一个类的数据成员时w运算符重载为了能直接对对象进行加减乘除等各种运算,经常需要将所定义的运算符运算函数声明为类的友元函数,以便可方便地访问类的私有成员w一个类从属于另一个类时(经常需要将一个类定义为另一个类的友元)第三十九页,本课件共有94页8.4 8.4 运算符重载运算符重载使用友元的注意事项使用友元的注意事项wfriend是单向的如果类A
20、是类B的友元,则类A可以访问类B的私有成员,但反之不成w友元不是类的成员友元不受类成员访问控制的限制,没有公有、保护、私有之分,它只是一个说明,可以放在类体内的任何地方w一个类的成员函数也可以成为另一个类的友元函数,此时的友元声明需要加上类域的限定第四十页,本课件共有94页8.4 8.4 运算符重载运算符重载例:将函数func()和类A的成员函数memfun()同时声明为类B的友元int func(int,float);/一个普通函数class Apublic:void memfunc(char*);/类A的成员函数 /;class Bfriend int func(int,float);fr
21、ieng void A:memfunc(char*);/类B的其它成员;注:友元的引用会破坏类的封装性,使用时应权衡利弊第四十一页,本课件共有94页8.4 8.4 运算符重载运算符重载运算符重载的函数可采用两种方式:w成员函数与友元函数成员函数与友元函数可以将运算符函数定义成类的成员函数也可以将运算符函数定义成友元函数第四十二页,本课件共有94页8.4 8.4 运算符重载运算符重载成员函数与友元函数的比较成员函数与友元函数的比较w成员函数成员函数有一个隐含的参数(this指针)如果将一个二元运算符定义为类的成员函数,则只需为这个函数说明一个参数。如果将一个一元运算符定义为类的成员函数,则这个函
22、数就不能再带参数。第四十三页,本课件共有94页8.4 8.4 运算符重载运算符重载w如果将一个重载的运算符定义为友元函数,则友元函数的参数个数和实际参数个数相同w成员函数与友元函数的相同点:成员函数与友元函数的相同点:二者都可以访问类的私有成员和保护成员第四十四页,本课件共有94页8.4 8.4 运算符重载运算符重载二元运算符的重载(以二元运算符的重载(以“+”为例)为例)w定义定义 作为类的成员函数,具有一个参数class COUNTERpublic:int operator +(COUNTER&c);作为友元函数,应有两个参数class COUNTERpublic:friend int o
23、perator +(COUNTER&c1,COUNTER&c2);第四十五页,本课件共有94页8.4 8.4 运算符重载运算符重载w函数实现函数实现 成员函数的实现int COUNTER:operator +(COUNTER&c)return value+c.value;友元函数的实现int operator +(COUNTER&c1,COUNTER&c2)return c1.value+c2.value;第四十六页,本课件共有94页8.4 8.4 运算符重载运算符重载w使用(二者相同)COUNTER c1(3),c2(4);/创建2个对象coutc1+c2;/输出7程序中出现的表达式:c1+
24、c2成员函数,编译程序将其解释为:c1.operator+(c2)友元函数,编译程序将其解释为:operator+(c1,c2)第四十七页,本课件共有94页8.4 8.4 运算符重载运算符重载一元运算符的重载一元运算符的重载(以(以“前缀前缀+”为例)为例)w定义定义用类成员函数用类成员函数class COUNTERpublic:COUNTER&operator +();COUNTER(int val)value=val;/构造函数 int getvalue()return value;private:int value;w定义定义用友元函数用友元函数class COUNTERpublic:f
25、riend COUNTER&operator +(COUNTER&c);类成员函数默认有一个参数,是调用该函数时所给的对象本身第四十八页,本课件共有94页8.4 8.4 运算符重载运算符重载函数实现函数实现w类成员函数的实现 COUNTER&COUNTER:operator +()value+;return *this;w友元函数的实现 COUNTER&operator +(COUNTER&c)c.value+;/因为是友元,所以可以访问私有成员valuereturn c;返回的是当前对象的引用,可以对当前对象再进行运算指针所指的对象(当前对象)必须给出哪个对象第四十九页,本课件共有94页8.
26、4 8.4 运算符重载运算符重载w使用方式COUNTER c(0);+c;coutc.getvalue();/输出1+(+c);coutc.getvalue();/输出3w成员函数与友元函数的使用方式是相同的注:如果不是用引用返回类型,则不能有上述操作和结果成员函数:成员函数:c.operator+()友元函数:友元函数:operator+(c)第五十页,本课件共有94页8.4 8.4 运算符重载运算符重载w赋值运算符的重载赋值运算符的重载/函数实现COUNTER&COUNTER&:operator =(COUNTER&c)value=c.value;return *this;/使用COUNT
27、ER c1(2),c2(5);c1=c2;/对象的赋值,调用赋值运算符重载函数注:用对象初始化对象调用拷贝构造函数,如:COUNTER c1=c2;当前对象可作为左值第五十一页,本课件共有94页8.4 8.4 运算符重载运算符重载w二元运算符与一元运算符二元运算符与一元运算符 成员函数 友元函数二元 1个参数(实际还是2个)2个参数一元 0个参数(实际还是1个)1个参数注:类对象本身(this)自动作为其成员函数的第一个参数第五十二页,本课件共有94页8.4 8.4 运算符重载运算符重载小小 结结1.重载运算符,可以是类的成员函数、友元函数或 普通函数(普通函数不常用)2.二者比较:参数的个数
28、不同访问成员的方式不同使用方式相同第五十三页,本课件共有94页8.4 8.4 运算符重载运算符重载 3.重载的运算符可以重新定义的有:4.重载的运算符不能重新定义的有:参数类型返回值类型参数个数优先级结合性新的运算符第五十四页,本课件共有94页附:总结几个常用概念w值返回与引用返回值返回与引用返回当需要将运算结果作为左值时,用引用返回(见下例)例:coutab;/作为左值,还能再用,就须用引用+(+a);/如果只用+a,可不用引用返回w参数用引用参数用引用参数用引用,不用复制对象副本,可节省内存,提高速度,还可改变参数的值例:COUNTER&operator+(COUNTER&c)w常量引用参
29、数常量引用参数不希望在函数中改变引用参数的值例:int COUNTER:operator+(const COUNTER&c)return value+c.value;/不希望改变参数c的值第五十五页,本课件共有94页附:函数的返回类型是引用举例/例:求两个数中的最小数#includeint&min(int&i,int&j)if(i=j)return i;elsereturn j;void main()int a=3,b=4;couta=a b=bendl;min(a,b)=5;couta=a b=bendl;min(a,b)=0;couta=a b=bfun();/调用哪个类的函数?如果是静态
30、绑定,就应调用BASE类的fun(),因为pobj是指向BASE类对象的指针,但现在pobj实际指向DERIVED类的对象,所以从道理上应调用DERIVED类的fun(),因此造成二者的矛盾第六十二页,本课件共有94页8.5 8.5 虚函数虚函数w解决的办法解决的办法virtual函数函数class BASE/virtual int fun();class DERIVED:public BASE/int fun();BASE *pobj;DERIVED dobj;pobj=&dobj;pobj-fun();/根据pobj当前所指的对象正确调用相应函数第六十三页,本课件共有94页8.5 8.5
31、虚函数虚函数w虚函数的含义虚函数的含义1、是一个类的成员函数2、可以为派生类对象使用3、派生类可以通过编写自己的成员函数来替代基类的虚函数,这种替代是基类预见到的,默认的,甚至是赞成的第六十四页,本课件共有94页8.5 8.5 虚函数虚函数w虚函数举例虚函数举例学生(Student)本科生(UnderGrad)研究生(PostGrad)硕士研究生(MasterGrad)博士研究生(DoctorGrad)第六十五页,本课件共有94页8.5 8.5 虚函数虚函数class STUDENTpublic:virtual void SeleteCourse();/选课 virtual int Calcu
32、Cridit();/计算总学分 /protected:char name30;int age;/;在定义STUDENT类时,已经预见到不同的学生选课的方式是不一样的,计算学分的方法也不一样 定义成virtual后,就允许派生类根据自己的需要重新定义成员函数第六十六页,本课件共有94页8.5 8.5 虚函数虚函数/UnderGrad本科生类没有重新实现两个虚函数,它是用基类的实现class UNDERGRAD:public STUDENTpublic:void practice();/工程实践private:;本科生使用基类的两个虚函数(基类中必须有两个虚函数的实现)第六十七页,本课件共有94页
33、8.5 8.5 虚函数虚函数/PostGrad研究生类重新实现两个虚函数class POSTGRAD:public STUDENTpublic:virtual void SeleteCourse();/选课 virtual int CalcuCridit();/计算总学分private:int SupervisorID;/导师 /;第六十八页,本课件共有94页8.5 8.5 虚函数虚函数/MasterGrad硕士生使用PostGrad提供的虚函数class MASTERGRAD:public POSTGRADpublic:/第六十九页,本课件共有94页8.5 8.5 虚函数虚函数/Doctor
34、Grad博士生类重新实现两个虚函数class DOCTORGRAD:public POSTGRADpublic:void SeleteCourse();/选课 int CalcuCridit();/计算总学分 /;第七十页,本课件共有94页8.5 8.5 虚函数虚函数w虚函数的好处虚函数的好处在基类中提供了一个接口,都用同样的调用方式。具体派生类如何实现,可由派生类去决定,既可以使用基类的实现,也可以不使用基类的实现,派生类定义自己的实现第七十一页,本课件共有94页8.5 8.5 虚函数虚函数void main()STUDENT *s;/s可能指向以下各种派生类对象/程序运行过程中动态创建学生
35、对象,可能是以下各种语句/s=new UNDERGRAD();/s=new POSTGRAD();/s=new DOCTORGRAD();/s=new MASTERGRAD();S-SeleteCourse();/调用POSTGRAD:SeleteCourse()因为 MASTERGRAD类中没有实现函数,调 用它的直接基类POSTGRAD中的函数/第七十二页,本课件共有94页8.5 8.5 虚函数虚函数virtual的含义的含义wvirtual只在类继承时才发辉作用wvirtual告诉编译器,它所修饰的函数需要动态绑定w在调用该函数时,需要根据对象的实际类型决定使用类继承层次中的哪个类的成员
36、函数(是哪个类的对象就调用哪个类的成员函数)第七十三页,本课件共有94页8.5 8.5 虚函数虚函数w使用虚函数的例子使用虚函数的例子/students存放所有学生的信息STUDENT *students3000;/指针数组int StudNum;/学生数目/在程序运行过程中动态创建了StudNum个学生对象/studentsStudNum+=new DoctorGrad();/studentsStudNum+=new UnderGrad();/第七十四页,本课件共有94页8.5 8.5 虚函数虚函数/所有学生选课void StudentSeleteCourse()for(int i=0;iS
37、eleteCourse();/程序非常简单学生学生本科生本科生研究生研究生硕士生硕士生博士生博士生复杂的实现复杂的实现虚函数虚函数第七十五页,本课件共有94页8.5 8.5 虚函数虚函数w如果不用虚函数,则程序会非常复杂void StudentSeleteCourse()for(int i=0;itype)case GRAD:/本科生studentsi-UNDERGRAD:SeleteCourse();break;case POST:/研究生studentsi-POSTGRAD:SeleteCourse();break;case DOCT:/博士生 /不仅麻烦,若再加一种学生还需修改程序,如果
38、用虚函 数就不用作任何改变,只加一个派生类.第七十六页,本课件共有94页8.5 8.5 虚函数虚函数虚函数的好处:多态性虚函数的好处:多态性主要体现在如下方面:w程序简单w设计与实现分开,实现了一定的封装在基类中设计高层逻辑、接口,具体实现细节由派生类根据各自需要实现,基类可以不用担心实现细节w程序可重用,易扩充 如:加一种学生,只需加一个派生类的虚函数实现w多态性语言的实现 体现“同一接口,多种方法”的多态性概念第七十七页,本课件共有94页8.5 8.5 虚函数虚函数虚函数的缺点:增加运行开销虚函数的缺点:增加运行开销(多占用内存空间)(多占用内存空间)w每个对象增加一个指针w调用虚函数时要
39、查表 虚函数的内部实现STUDENT:SeleteCoursePOSTGRAD:SeleteCourseDOCTORGRAD:SeleteCourseMASTERGRAD:SeleteCourseV-table 虚拟表虚拟表(所有虚函数都在此表中)nameage.V-pointer学生对象学生对象所有对象都有一个指针如果没有虚函数,则对象没有这个特殊成员第七十八页,本课件共有94页8.5 8.5 虚函数虚函数使用虚函数的注意事项使用虚函数的注意事项w派生类中重新定义基类中的虚成员函数,必须在函数原型上与基类中的虚成员函数保持一致w派生类对象调用虚函数时,如果该虚函数在派生类中重新定义了,则执行
40、派生类所定义的操作,否则执行基类中所定义的操作w基类中的非虚函数不能在派生类中重新(覆盖)定义w派生类中的虚函数,virtual关键字可有可无,如果下一级派生类还需要使用时,则必须有virtualw调用虚函数操作的是指向对象的指针或对象引用(调用虚函数的参数只能是对象指针或对象引用)第七十九页,本课件共有94页8.5 8.5 虚函数虚函数例:虚函数例:虚函数#includeclass POINTpublic:POINT(int x1,int y1)x=x1;y=y1;virtual int area()return 0;private:int x,y;第八十页,本课件共有94页8.5 8.5
41、虚函数虚函数class RECT:public POINTpublic:RECT(int x1,int y1,int l1,int w1):POINT(x1,y1)l=l1;w=w1;int area()/虚函数 return l*w;private:int l,w;第八十一页,本课件共有94页8.5 8.5 虚函数虚函数void fun(POINT&p)coutp.area()endl;void main()RECT rec(2,4,10,6);fun(rec);程序执行结果:60说明:1、fun函数的引用对象参数p被动态绑定,该函数体内调用的area()在运行中被确定为RECT类中的are
42、a函数2、该程序中如果没有virtual关键字,则为静态绑定,输出结果为0第八十二页,本课件共有94页8.6 8.6 纯虚函数与抽象类纯虚函数与抽象类w纯虚函数纯虚函数是一种特殊的虚函数w纯虚函数的定义格式纯虚函数的定义格式在基类的虚函数原型的分号前加“=0”例:class POINT public:virtual int area()=0;/;第八十三页,本课件共有94页8.6 8.6 纯虚函数与抽象类纯虚函数与抽象类纯虚函数的特点纯虚函数的特点w纯虚函数是将要被派生类实现的函数(纯虚函数只有函数原型,没有函数实现)w具有纯虚函数的类不能实例化(不能创建对象,因为这种类不完整)w派生类中如果
43、还有纯虚函数,则还不能实例化,能实例化的派生类必须实现所有纯虚函数第八十四页,本课件共有94页8.6 8.6 纯虚函数与抽象类纯虚函数与抽象类纯虚函数的作用纯虚函数的作用w为抽象基类的定义提供了手段w为所有派生类设计一个标准接口,方便高层应用逻辑的设计第八十五页,本课件共有94页8.6 8.6 纯虚函数与抽象类纯虚函数与抽象类例:例:学生选课class ABSTRACT_STUDENTpublic:virtual void SeleteCourse()=0;virtual int CalcuCridit()=0;/protected:char name30;int age;/;纯虚函数纯虚函数
44、没有实现,只有接口带有纯虚函数的类不能实例化第八十六页,本课件共有94页8.6 8.6 纯虚函数与抽象类纯虚函数与抽象类/UNDERGRAD必须实现基类的纯虚函数class UNDERGRAD:public ABSTRACT_ STUDENTpublic:void SeleteCourse();int CalcuCridit();void practice();/工程实践 /;/UNDERGRAD 类可以实例化第八十七页,本课件共有94页8.6 8.6 纯虚函数与抽象类纯虚函数与抽象类/POSTGRAD类可以保持两个纯虚函数的定义class POSTGRAD_ABSTRACT:public A
45、BSTRACT_ STUDENTpublic:void SeleteCourse()=0;int CalcuCridit()=0;/private:int supervisorID;/导师;/该类也不能实例化第八十八页,本课件共有94页8.6 8.6 纯虚函数与抽象类纯虚函数与抽象类/DOCTORGRAD类必须实现两个虚函数class DOCTORGRAD:public ABSTRACT_POSTGRADpublic:void SeleteCourse();int CalcuCridit();/;/DOCTORGRAD 类可以实例化第八十九页,本课件共有94页纯虚函数举例纯虚函数举例#incl
46、ude#includeclass BASEpublic:virtual void setx(int i,int j=0)/虚函数x=i;y=j;virtual void disp()=0;/纯虚函数protected:int x,y;第九十页,本课件共有94页class SQUARE:public BASE/平方public:void disp()coutx=x:;coutx square=x*xendl;class CUBE:public BASE/立方public:void disp()coutx=x:;coutx cube=x*x*xendl;第九十一页,本课件共有94页class CH
47、POW:public BASE/n次方public:void disp()coutx=xy=y:;coutpow(x,y)=pow(double(x),double(y)setx(5);ptr-disp();/调用SQUARE类中的disp()ptr=&c;ptr-setx(6);ptr-disp();/调用CUBE类中的disp()ptr=&d;ptr-setx(3,4);ptr-disp();/调用CHPOW类中的disp()第九十三页,本课件共有94页8.6 8.6 纯虚函数与抽象类纯虚函数与抽象类抽象类的使用规定:抽象类的使用规定:w抽象类只能用作其他类的基类,不能建立抽象类的对象w抽象类不能用作参数类型,函数返回类型w可以说明指向抽象类的指针和引用,该指针可以指向它的派生类,进而实现多态类第九十四页,本课件共有94页