《第16章多态性精选文档.ppt》由会员分享,可在线阅读,更多相关《第16章多态性精选文档.ppt(32页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、第16章多态性本讲稿第一页,共三十二页-多态性-2主要内容n多态性的概念和多态类型 n联编n虚函数n抽象类 n运算符重载*本讲稿第二页,共三十二页-多态性-3多态性的概念 n多态性是面向对象程序设计的重要特征之一,多态性是面向对象程序设计的重要特征之一,是实现是实现“一种接口,多种方法一种接口,多种方法”的技术。的技术。nC+C+的多态性是指对的多态性是指对同一条同一条消息,被消息,被不同不同类型类型的对象接收将产生的对象接收将产生不同不同的行为。的行为。本讲稿第三页,共三十二页-多态性-4在在C+中有两中有两种多态种多态性性 编译时的多态性编译时的多态性 运行时的多运行时的多态性态性 运行时
2、的多态性是指在程序执行前,运行时的多态性是指在程序执行前,无法根据函数名和参数来确定该调用无法根据函数名和参数来确定该调用哪一个函数,必须在程序执行过程中,哪一个函数,必须在程序执行过程中,根据执行的具体情况来动态地确定。根据执行的具体情况来动态地确定。它是它是通过类继承关系和虚函数来实现的。通过类继承关系和虚函数来实现的。目的也是建立一种通用的程序目的也是建立一种通用的程序。通用。通用性是程序追求的主要目标之一。性是程序追求的主要目标之一。通过函数的重载和运算符通过函数的重载和运算符的重载来实现的。的重载来实现的。多态的类型本讲稿第四页,共三十二页-多态性-5联编 n多态性的实现过程中,确定
3、调用哪个同名函数的过程就是联编(binding),又称绑定。n联编是指计算机程序自身彼此关联的过程,也就是把一个标识符名和一个存储地址联系在一起的过程。用面向对象的术语讲,就是把一条消息和一个对象的方法相结合的过程。n按照联编进行的阶段的不同,可以分为静态联编和动态联编,这两种联编过程分别对应着多态性的两种实现方式。本讲稿第五页,共三十二页-多态性-6静态联编 n在在编译阶段编译阶段完成的联编称为静态联编。完成的联编称为静态联编。n在编译过程中,编译系统可以根据类型匹配等特征来确在编译过程中,编译系统可以根据类型匹配等特征来确定程序中调用操作与执行某个同名函数实现之间的关系,定程序中调用操作与
4、执行某个同名函数实现之间的关系,即确定某一个同名函数到底是要调用即确定某一个同名函数到底是要调用哪一段函数实现代哪一段函数实现代码。码。n函数重载和运算符重载就是通过静态联编方式实现函数重载和运算符重载就是通过静态联编方式实现的编译时的多态的体现。的编译时的多态的体现。n静态联编的优点是函数调用速度快、效率较高,缺点是编静态联编的优点是函数调用速度快、效率较高,缺点是编程不够灵活程不够灵活。本讲稿第六页,共三十二页-多态性-7动态联编 n只有在运行程序时才能确定将要调用的函数。只有在运行程序时才能确定将要调用的函数。这种在这种在运行阶段运行阶段进行的联编称为动态联编。进行的联编称为动态联编。动
5、态多态性必须存在于继承的环境之中。n动态联编的优点是提供了更好的编程灵活性、动态联编的优点是提供了更好的编程灵活性、问题抽象性和程序易维护性,缺点是与静态联问题抽象性和程序易维护性,缺点是与静态联编相比,函数调用速度慢。编相比,函数调用速度慢。本讲稿第七页,共三十二页-多态性-8虚函数 n虚函数是动态联编的基础。n在继承体系中,如果在派生类中要对所继承的成员函数重新定义其功能,该函数应在基类中被定义为虚函数。n虚函数是非静态的成员函数,经过派生之后,虚函数在类族中可以实现运行时的多态性。本讲稿第八页,共三十二页-多态性-9虚函数的声明 n虚函数是一个在某基类中声明为virtual并在一个或多个
6、派生类中被重新定义的成员函数。声明虚函数的格式如下:virtual virtual (););本讲稿第九页,共三十二页-多态性-10虚函数的使用(一)n虚函数仅适用于有继承关系的类对象,所以只有类的成员函虚函数仅适用于有继承关系的类对象,所以只有类的成员函数才能说明为虚函数。数才能说明为虚函数。n静态成员函数,是所有同一类对象共有,不受限于某个对静态成员函数,是所有同一类对象共有,不受限于某个对象,不能作为虚函数。象,不能作为虚函数。n内联函数每个对象一个拷贝,无映射关系,不能作为虚内联函数每个对象一个拷贝,无映射关系,不能作为虚函数。函数。本讲稿第十页,共三十二页-多态性-11虚函数的使用(
7、二)n构造函数不能被定义为虚函数。构造函数不能被定义为虚函数。n析构函数可以是虚函数。析构函数可以是虚函数。在基类中及其派生类中都在基类中及其派生类中都动动态分配内存空间时,必须把析构函数定义为虚函数,态分配内存空间时,必须把析构函数定义为虚函数,实现撤消对象时的多态性。实现撤消对象时的多态性。(这样,才有可能通过基类(这样,才有可能通过基类指针删除派生类对象,调用对象的析构函数撤消指针删除派生类对象,调用对象的析构函数撤消动态分动态分配的内存空间配的内存空间)本讲稿第十一页,共三十二页-多态性-12虚函数的使用(三)n关键字关键字virtualvirtual指明该成员函数为虚函数。指明该成员
8、函数为虚函数。如果如果虚函数虚函数定义放在类外,定义放在类外,virtual只能加在函数声明前面只能加在函数声明前面。n派生类中定义虚函数必须与基类中的虚函数派生类中定义虚函数必须与基类中的虚函数同名、同同名、同参数表、同返回类型,参数表、同返回类型,只能修改只能修改函数体函数体内容内容。否则被。否则被认为是重载,而不是虚函数。如认为是重载,而不是虚函数。如基类中返回基类指针,基类中返回基类指针,派生类中返回派生类指针是允许的派生类中返回派生类指针是允许的,这是一个例,这是一个例外。外。本讲稿第十二页,共三十二页-多态性-14纯虚函数 n在在C+C+中,有一个仅为多态机制提供一个接口而中,有一
9、个仅为多态机制提供一个接口而没有任何实体定义的函数,被称为纯虚函数。没有任何实体定义的函数,被称为纯虚函数。n纯虚函数纯虚函数是指被标明为不具体实现的虚拟成员是指被标明为不具体实现的虚拟成员函数。它用于这样的情况:定义一个基类时,函数。它用于这样的情况:定义一个基类时,会遇到无法定义基类中虚函数的具体实现,其会遇到无法定义基类中虚函数的具体实现,其实现依赖于不同的派生类。声明纯虚函数的一实现依赖于不同的派生类。声明纯虚函数的一般格式如下:般格式如下:virtual virtual ()=0)=0;本讲稿第十四页,共三十二页-多态性-15纯虚函数 1 1、定义纯虚函数时,、定义纯虚函数时,不能定
10、义虚函数的实现部分不能定义虚函数的实现部分。即使是函数。即使是函数体为空也不可以,函数体为空就可以执行,只是什么也不做体为空也不可以,函数体为空就可以执行,只是什么也不做就返回。而就返回。而纯虚函数不能调用纯虚函数不能调用。2 2、“=0=0”表明程序员将不定义该函数,函数声明是为派生类保留表明程序员将不定义该函数,函数声明是为派生类保留一个位置。一个位置。“=0=0”本质上是将指向函数体的本质上是将指向函数体的指针定为指针定为NULLNULL。3 3、含有纯虚函数的基类是不能用来定义对象的。纯虚函数没有、含有纯虚函数的基类是不能用来定义对象的。纯虚函数没有实现部分,不能产生对象,所以含有纯虚
11、函数的类是抽象类。实现部分,不能产生对象,所以含有纯虚函数的类是抽象类。在派生类中必须有重新定义的纯虚函数的函数体,这样的派在派生类中必须有重新定义的纯虚函数的函数体,这样的派生类才能用来定义对象。生类才能用来定义对象。本讲稿第十五页,共三十二页-多态性-16抽象类(一)n作用q抽象类为抽象和设计的目的而声明,将有关的数据和行为组织在一个继承层次结构中,保证派生类具有要求的行为。q对于暂时无法实现的函数,可以声明为纯虚函数,留给派生类去实现。n注意q抽象类只能作为基类来使用。q不能声明抽象类的对象。本讲稿第十六页,共三十二页-多态性-17抽象类(二)n抽象类是为了抽象和设计的目的而建立的,主要
12、作用是将有关抽象类是为了抽象和设计的目的而建立的,主要作用是将有关的派生类组织在一个继承层次结构中,由抽象类为它们提供一的派生类组织在一个继承层次结构中,由抽象类为它们提供一个个公共的根公共的根,相关的派生类就从这个根派生出来。抽象类为一类族,相关的派生类就从这个根派生出来。抽象类为一类族提供统一的操作界面。提供统一的操作界面。n抽象类是一种特殊的类,专门作为基类派生新类。在抽象类的定抽象类是一种特殊的类,专门作为基类派生新类。在抽象类的定义中义中至少有一个纯虚函数。至少有一个纯虚函数。自身无法实例化自身无法实例化,即不能建立抽象类对象;,即不能建立抽象类对象;不能用作参数类型、函数返回值类型
13、或显式转换的类型;不能用作参数类型、函数返回值类型或显式转换的类型;但可以说明指向抽象类的但可以说明指向抽象类的指针或引用,该指针或引用可以指向抽象类的指针或引用,该指针或引用可以指向抽象类的派生类,进而实现多态性。派生类,进而实现多态性。本讲稿第十七页,共三十二页-多态性-18举例举例 1#include const double PI=3.14159;class Shapes/形状类,作为基类形状类,作为基类protected:float x,y;float s;public:void setvalue(float d,float w=0)x=d;y=w;void disp()cout T
14、he area is:ssetvalue(10,5);ptr0-disp();/抽象类指针调用派生类成员函数抽象类指针调用派生类成员函数 ptr1=&c1;ptr1-setvalue(10);ptr1-disp();/抽象类指针调用派生类成员函数抽象类指针调用派生类成员函数return 0;本讲稿第十九页,共三十二页-多态性-20运算符重载 n运算符重载就是赋予系统预定义的运算符多重含义,使同一个运算符作用于不同类型的数据导致不同的行为。n运算符重载的实质就是函数重载。n运算符重载使得系统预定义的运算符能作用于用户自定义类型的数据,进行类似运算。本讲稿第二十页,共三十二页-多态性-21运算符重
15、载规则(一)nC+的运算符除了少数几个之外,全部可以重载,而且只能重载已有的运算符,不可臆造新的运算符。n重载运算符坚持4个“不能改变”:不能改变运算符操作数的个数;不能改变运算符的优先级;不能改变运算符的结合性;不能改变原运算符的语法结构。参数和返回值类型可以重新说明。本讲稿第二十一页,共三十二页-多态性-22运算符重载规则(二)n运算符重载是针对新类型数据的实际需要,对原有运算符进行适当的改造。n运算符重载有两种方式:重载为类的成员函数和重载为类的友元函数。一般情况下,单目运算符最好重载为成员函数;双目运算符则最好重载为友元函数;有些双目运算符重载为成员函数较好,如:赋值运算符=。本讲稿第
16、二十二页,共三十二页-多态性-23运算符重载为成员函数 n运算符重载为类的成员函数的一般格式如下:n其中,operator是定义运算符重载函数的关键字。中最多有一个形参。operator operator();本讲稿第二十三页,共三十二页-多态性-24运算符重载为成员函数 n运算符重载函数的函数名必须为关键字运算符重载函数的函数名必须为关键字OperatorOperator加一个合法的运算符。加一个合法的运算符。n重载重载二元二元运算符运算符时,时,只只显式说明一个参数显式说明一个参数;左左操作数一定是类的对象操作数一定是类的对象,由由this指针指针(指向调用(指向调用该成员函数的对象)提供
17、;该成员函数的对象)提供;右操作数右操作数是函数的是函数的实参实参。n经重载后,含有双目运算符经重载后,含有双目运算符 B的表达式的表达式 oprd1 B oprd2 相当于相当于 oprd1.operator B(oprd2)。其其中中 oprd1 为类的对象,为类的对象,oprd2是是函数的参数。函数的参数。本讲稿第二十四页,共三十二页-多态性-25运算符重载为成员函数 n重载重载单目运算符的成员单目运算符的成员函数没有参数。函数没有参数。经重载经重载后,含单目运算符后,含单目运算符U的表达式的表达式 U oprd 相当于相当于 oprd.operator U()。其中其中 oprd 为类
18、的对象。为类的对象。n因为重载单目运算符因为重载单目运算符没有参数,没有参数,所以重载所以重载“+”和和“-”运算符时,不能区分是前缀操运算符时,不能区分是前缀操作还是后缀操作。作还是后缀操作。C+约定,在参数表中放上约定,在参数表中放上一个整型参数一个整型参数int,表示为后缀运算符重载。,表示为后缀运算符重载。本讲稿第二十五页,共三十二页-多态性-26运算符运算符运算符名称运算符名称禁止重载的理由禁止重载的理由?:三三目目条条件件运运算算符符C+中没有定义三目运算符的语法中没有定义三目运算符的语法.成员操作符成员操作符为为保保证证成成员员操操作作符符对对成成员员访访问问的的安安全性全性:作
19、用域操作符作用域操作符该操作符右操作数不是表达式该操作符右操作数不是表达式sizeof类类型型字字长长操操作作符符该该操操作作符符的的操操作作数数为为类类型型名名,不不是是表达式表达式C+中不允许重载的运算符中不允许重载的运算符本讲稿第二十六页,共三十二页-多态性-27举例:操作符重载举例:操作符重载#include#include class Complex /定义复数类double Real,Image;public:/定义构造函数Complex(double r=0.0,double i=0.0):Real(r),Image(i)Complex(Complex&com)/定义拷贝构造函数
20、Real=com.Real;Image=com.Image;static void Print(Complex&ob);void operator=(Complex);Complex operator+(Complex);Complex operator+(double);/*void operator+=(Complex);double abs(void);Complex operator*(Complex);Complex operator/(Complex);*/;本讲稿第二十七页,共三十二页-多态性-28Complex Complex:operator+(Complex c)Compl
21、ex Temp(Real+c.Real,Image+c.Image);return Temp;Complex Complex:operator+(double d)return Complex(Real+d,Image);void Complex:operator=(Complex c)Real=c.Real;Image=c.Image;本讲稿第二十八页,共三十二页-多态性-29int main()Complex c1(1.0,1.0),c2(2.0,2.0),c3(4.0,4.0),c;double d=0.5;Complex:Print(c1);c=c2+c3;/表达式表达式c2+c3等同
22、于等同于c2.operator+(c3)Complex:Print(c);c=c+d;Complex:Print(c);return 0;本讲稿第二十九页,共三十二页-多态性-30运算符重载为友元函数 n运算符重载为类的友元函数的一般格式如下:n其中,最多有两个形参。下列运算符不能重载为友元函数:=、()、-friend friend operator operator();本讲稿第三十页,共三十二页-多态性-31运算符重载为友元函数 n双目运算符 B重载为友元函数后,表达式oprd1 B oprd2 等同于按以下方式调用函数:operator B(oprd1,oprd2)本讲稿第三十一页,共
23、三十二页-多态性-32课外作业类的继承与多态:定义一个Point类,该类有点的坐标值x,y的属性;设置、获取、输出属性值的功能;作为多个图形类的基类,还预留有计算图形面积的功能接口。定义Point类的两个派生类:Rectangle类和Circle类。Rectangle类有新属性是矩形的长和宽,它从Point类继承的属性x、y是矩形的左上角顶点的坐标;Circle类有新属性是圆的半径,它从Point类继承的属性x、y是圆心的坐标;Rectangle类和Circle类的新功能是设置、获取、输出新属性和计算并返回图形面积。编程序,定义以上类,定义类的对象,分别求矩形和圆的面积。本讲稿第三十二页,共三十二页