函数函数与运算符的重载.ppt

上传人:牧羊曲112 文档编号:6244202 上传时间:2023-10-09 格式:PPT 页数:38 大小:238.49KB
返回 下载 相关 举报
函数函数与运算符的重载.ppt_第1页
第1页 / 共38页
函数函数与运算符的重载.ppt_第2页
第2页 / 共38页
函数函数与运算符的重载.ppt_第3页
第3页 / 共38页
函数函数与运算符的重载.ppt_第4页
第4页 / 共38页
函数函数与运算符的重载.ppt_第5页
第5页 / 共38页
点击查看更多>>
资源描述

《函数函数与运算符的重载.ppt》由会员分享,可在线阅读,更多相关《函数函数与运算符的重载.ppt(38页珍藏版)》请在三一办公上搜索。

1、1,函数在C+程序设计中的意义体现在四个方面:,(1)从历史上说,函数的思想来源于子程序,把程序中反复出现的相同或相近的程序改写成子程序,可以大大缩短程序的长度。函数实际上是参数化的子程序。,(2)从结构化程序设计(SP)的观点来看,更重要的是通过函数设计,可以把整个程序要完成的整体的复杂的计算任务,分解为一个个较小的,相对简单的子任务。这种模块化的程序易设计,易阅读,易调试,易维护,较少出错。,(3)从运算的角度说,函数就是C+语言提供的由用户定义的运算。运算符是系统提供的运算,而函数是由用户自己定义的运算。,2,(4)作为面向对象程序设计(OOP)语言的C+,以类为核心,类由数据和方法组成

2、,方法就是对数据的运算和处理,亦即类的函数成员。故函数设计同样是OOP 的重要组成部分。,5.1 三次方程求根程序的设计,5.2 函数的说明与使用,5.2.1 函数说明,C+程序允许两种函数说明语句的形式,我们把它们分别称为函数原型(或函数声明)和函数定义。,3,1函数原型 函数原型用来指出函数的名称、类型和参数,其格式为:();,属性说明:可缺省,一般可以是下面的关键字之一:inline,static,virtual,friend 等。inline 表示该函数为内联函数;static 表示该函数为静态(内部)函数;virtual 表示该函数为虚函数;friend 表示该函数为某类(class

3、)的友元函数。,4,函数原型一般在两种情形下被使用:在程序中某函数的调用语句出现在该函数的定义之前,这时必须在调用语句之前列出函数原型。为了类定义的简明清晰,一般把较大的函数成员定义移到类说明之外,这时应把该函数的原型列于类说明之中。,5,2函数定义 函数定义与函数原型的主要区别是它还包括函数体,其格式为:属性说明类型函数名(参数表)函数体 属性说明,返回类型,函数名与函数原型一致,参数表中不可省略参数名。函数体:由和括起来的复合语句即程序块。,6,5.2.2 函数调用,函数调用是已定义函数的一次实际运行,与某类型的一个变量,某类的一个对象类似,函数调用也是函数定义的一个“实例”。函数调用的两

4、要素是函数名和实参表。具体的调用实施过程如下:,(1)根据调用语句中的函数名在整个程序中搜索同名函数定义;(2)对实参数的参数个数,类型,顺序进行核对,判定是否与函数定义中的形参表对应一致,,7,(3)根据参数的类型(值参数或引用参数)进行值参数的值传递或引用参数的换名;(4)运行函数体代码;(5)返回调用点,并返回所要求的函数值。,5.2.3 函数的返回,函数的返回完成两项任务:把运行控制从函数体返回到函数调用点。根据返回值要求,返回所需要的数据值。,8,函数的返回值有下面几种情形:1.返回void 类型 如果函数无值返回,应说明为void 类型。2返回数值类型 最常见的函数是返回一个数值的

5、函数。3返回引用类型 值返回方式是C 和Pascal 语言中唯一的返回方式,C+语言提供的引用返回概念是其特有的一种很强的功能,当函数定义中把该函数说明为某类型的引用类型时,该函数调用后返回的不单是值,而是包含返回值的变量(或对象)。,9,5.2.4 函数的参数,C+语言允许函数无参、有一个或多个参数,而且还支持不定个数参数的函数。,无参函数:其函数说明为下列形式:void print(void);int getx();用void 或空表示无参。,(2)一个或多个参数:,(3)不定个数参数:,有些应用问题中参数个数是变化的。处理参数个数不定的情形,可有不同的途径。,10,如:void sort

6、(int n,float*a);这个函数可对n 长的浮点数组进行排序,n 是变化的;由于a 是数组的首地址,因此这个函数实际上是可以进行对任意多个浮点数排序的处理。,C+语言有的版本还提供一些库函数,支持处理形如:void abc(int i,);的不定参数函数。,C+语言,允许参数表中包含无名参数,主要是为了区分函数,例如:int f(int a,int b)return ab*b;int f(int a,int b,int)return a*ab;两个不同的函数同名,但由于第二个函数包含一无名参数,使得在调用时能够被区分,f(x,y)是第一个函数的调用,f(x,y,0)是第二个函数的调用。

7、,11,C+程序还允许为函数定义可缺省参数(即参数有默认值。当对应的实参缺省时,该形参将使用默认值。),这种函数调用时具有灵活性,例如:int sqrsum(int a,int b,int c0)return a*ab*bc*c;其中参数c 为可缺省参数,下面的调用方式都是合法的(x,y,z 为int 型变量):sqrsum(x,y,z)sqrsum(xy,xy)sqrsum(x,y)参数表中可有任意多个参数指定为可缺省参数,但所有可缺省参数必须列后。在调用该函数时,只能缺省后面的可缺省参数。,可缺省参数例:p5_3.cpp,12,5.2.5 值调用与引用调用,C+语言在进行函数调用时,对参数

8、的处理有两种方式,即值调用方式和引用调用方式。前者是普通的形式,在C 语言中只有这种方式;C+语言中增加了引用调用形式,这种形式与pascal 语言中的变量参数调用方式相似。,1 赋值调用方式(值调用方式),在函数定义的参数中,除了被说明为引用(&)的参数之外,其余所有类型的形参都属于赋值形参。凡是赋值形参,在函数的每次调用时,都必须为每一个赋值形参创建一个新的参数变量。,13,函数调用语句中,与赋值形参相对应的实参可以是指定类型的常量、变量或表达式。为赋值形参创建的参数变量是局限于函数体运行的局部变量,它作为该形参的一个实例,参加函数体程序块的这次运行,一旦运行完毕,这个参数变量就被撤消。实

9、参与形参即使同名,也没有直接的关系。调用该函数,仅仅传递实参的值,实参本身与函数调用过程无关,在调用之后其值不会改变。当一个函数有多个赋值形参时,在进行值传递过程中,多个实参表达式计算的次序将依赖于具体的编译系统。,例如:realpara(n+,n-);,14,2引用调用方式,引用形参:函数定义的参数表中,名字前加上符号的参数为引用形参。,例如:void swap(inta,intb)int tempa;ab;btemp;形参a,b 为引用形参,这时其函数原型可写为:void swap(int,int);,15,引用形参在调用过程中的参数传递机制不同于赋值形参。其要点是:,(1)函数的调用语句

10、中对应于引用形参的实参必须是同一类型的变量,非变量的表达式则不允许。(2)参数传递的内容不是实参的值,而是地址,其实际的效果是令对应的引用形参在调用过程中,作为一个变量名指向作为实参的这个变量,与赋值形参的不同在这里体现出来,在引用调用过程中并不创建新的参数变量!(3)在函数体程序块的运行中,引用形参的每次出现,由于它现在已经是指向实参变量,因此相当于全用实参变量所代替。即起到了所谓的“换名”的作用。,16,(4)在函数体程序运行结束,控制转回调用点时,该引用形参与实参变量的对应关系也就终止了。但是在调用过程中对于这个实参变量的所有处理和操作的结果,却保留下来。这一点也是区别于赋值调用的。它不

11、需要借助于指针类型,直接可以把函数处理结果带出函数。,C+语言提供的引用调用方式,表面上看它与利用指针类型的形参的赋值调用所起的效果相同,实际上它优于指针方法。,使用指针方法示例:void swap(int*a,int*b)int temp*a;*a*b;*btemp;,17,设计函数在下面两种情形时,建议采用引用参数。,需要改变某些变量的值(上述函数swap 就是一例);对于占内存较多的参数(如数组,对象参数)为了不另建新的参数变量以节省内存。,在后一种情况,为了保证实参不在函数中被修改,可在形参说明中加上const 说明(在函数体中不能改变其值)。而对于赋值形参,则无此必要。,例如:com

12、plex add(const complexa,const complexb);,值调用与引用调用例:p5_2.cpp,18,5.2.6 内联函数,内联(inline)函数的设置是C+不同于C 的特征之一。(1)在C+程序中符合下列条件之一的函数为内联函数:函数说明前冠以“inline”关键字的函数;类内定义的函数成员。(第7章介绍)(2)在编译过程中,凡内联函数,系统把它的执行代码插入到该函数的每个调用点,从而使程序执行过程中,每次调用该函数时不需控制转移,但该函数代码可能有多个拷贝出现在目标程序中。,19,(3)一般把函数体短小而又频繁调用的函数说明为内联函数较好。内联函数体内一般不能有循

13、环语句和switch语句。内联函数的定义必须出现在第一次调用之前。对内联函数不能进行异常接口声明。(4)利用编译预处理的宏定义方式,也可以实现类似于内联函数的功能。不过,宏定义方式没有类型的概念,是不安全的;内联函数的方式更为方便和可靠。,20,5.3 函数的嵌套与递归,5.3.1 函数嵌套,一个函数的函数体中包含一个或多个函数调用语句,即称为函数嵌套。函数嵌套调用所占用的空间(如赋值参数的创建等等)用堆栈(stack)的方式管理。一般这种堆栈所分配的空间是有限的,因此函数互相嵌套的层数也是有限的,依编译系统不同,其允许的嵌套层数也可能不同。,21,嵌套调用和返回示图:,调用f1函数,结束,f

14、1函数,调用f2函数,结束,f2函数,结束,22,5.3.2 函数的递归,函数A 在其函数体中直接包含它自己的调用语句,函数A 称为(直接)递归函数。函数A 在其函数体中间接地包含对它自己的调用,例如A 调用函数B,但函数B 又调用函数A,则函数A 称为(间接)递归函数。无论是直接递归还是间接递归都必须保证在有限次调用之后能够结束。函数调用时系统要付出时间和空间代价,在功能相同的情形下,总是非递归程序效率较高。,23,/*利用递归调用求n!的函数*/float fac(int n)float f;if(n=1)f=1;else f=fac(n-1)*n;return f;,计算4!(fac(4

15、))的递归过程图:,return f(使fac(1)=1),return f(使fac(2)=2),return f(使fac(3)=6),return f(使fac(4)=24),24,5.4 函数与运算符的重载,函数重载实际上是函数名重载,即支持多个不同的函数采用同一名字。(这一点在C 语言和其它语言中是不允许的。)函数的重载并不是为了节省标识符,而是为了方便程序员的使用。,5.4.1 函数重载,实现函数的重载必须满足下列条件之一;(1)参数表中对应的参数类型不同;(2)参数表中参数个数不同:(3)参数表中不同类型参数的次序不同。,重载函数例程:p5_0.cpp,25,在定义同名函数时应注

16、意:,(1)返回类型不能区分函数。例如:float add(int,float);int add(int,float);/错误(2)采用引用参数不能区分函数。例如:void print(double);void print(double);/错误 void print(const double);/错误(3)有些派生基本类型的参数虽然可以区分同名函数,但在使用中必须注意可能出现二义性。,26,(4)包含可缺省参数时,可能造成二义性,程序设计中应避免这种情形出现。例如:int sum(int a,int b,int c0);int sum(int a,int b);(5)参数名不能区分函数。例如

17、:int sum(int a,int b);int sum(int x,int y);(6)不要将不同功能的函数定义为重载函数,以免出现对调用结果的误解,但语法上是允许的。,27,遇到无准确匹配的函数定义时,C+系统并不马上按出错处理,它按下面的方式处理:(1)通过数组名与指针变量,函数名与函数指针,某类型变量与const 常量之间的转换,再查是否可实现匹配;(2)把实参类型从低到高(按字长由短到长)进行基本类型及其派生类型的转换,再检查是否可匹配;(3)查有无已定义的可变个数参数的函数,如有把它归为该函数。在进行上述尝试性的处理之后可能出现仍无匹配或匹配不唯一的情况,这时可能输出出错信息或错

18、误地运行。,28,5.4.2 运算符重载,C+语言规定,大多数运算符都可以重载,包括:,单目运算符:-,!,+,-,new,delete双目运算符:+,-,*,(算术运算),(位运算)&,|(逻辑运算)=,!=,=(关系运算),*,(赋值运算),(赋值运算),(逗号运算),(IO 运算)(),(其它),29,不可重载运算符包括:,限定符.:条件运算符?:取长度运算符 sizeof,算术运算符,逻辑运算符,位运算符和关系运算符中的,这些运算都与基本数据类型有关,通过运算重载函数的定义,使它们也用于某些用户定义的数据类型。,赋值运算符,关系运算符,!,指针运算符和*,下标运算符等,它们的运算所涉及

19、的数据类型按C+程序规定,并非只限于基本数值类型。因此,这些运算符可以自动地扩展到任何用户定义的数据类型,一般不需作重载定义就可“自动”地实现重载。,30,重载之后,运算符的优先级和结合性不会改变。一般来讲,重载的功能应与原有功能相类似,不能改变原运算符的操作数个数,同时至少要有一个操作对象是用户自定义类型。运算符重载的一般语法形式为:函数类型 operator 运算符(形参表)运算符重载函数的调用方式有两种:(1)与原运算符相同的调用方式。如b1+b2,b1*b2(2)一般函数调用方式。如b1+b2,也可以写为operator+(b1,b2),例:复数加减:p5_1.cpp,31,在C+中运

20、算符的重载一般针对类,重载有两种形式:重载为类的成员函数和重载为类外函数。当重载为类的成员函数时,函数的参数个数比原来的操作数个数要少一个(后缀+、-除外);当重载为类外函数时,函数的参数个数与原来的操作数个数相等。单目运算符+和-实际上各有两种用法,前缀增(减)量和后缀增(减)量。其运算符重载函数的定义当然是不同的,对两种不同的运算无法从重载函数的原型上予以区分:函数名(operator+)和参数表完全一样。为了区别前缀+和后缀+,C+语言规定,在后缀+的重载函数的原型参数表中增加一个int 型的无名参数。其原型形式为:,32,前缀+类型operator+()/作为类成员 类型operato

21、r+(类型)/作为类外函数后缀+类型operator+(int)/作为类成员 类型operator+(类型,int)/作为类外函数关于减量运算符的重载方式相同。其调用方法为:前缀+a 或a.operator+()operator+(a)后缀+a+或a.operator+(0)operator+(a,0),33,5.5 函数与C+程序结构,5.5.1 库函数的使用,库函数又叫标准函数,程序员可直接调用,但要在程序开头说明库函数所在的头文件。如:#include#include,SP框架结构5.5.3 函数间的数据传递,通过赋值参数和返回语句通过全局变量通过指针类型参数和引用型参数通过数组类型参数

22、(本质上与指针类型参数相同),34,5.5.4 变量与函数的作用域,1.外部存储属性与静态存储属性,整个程序(外部函数、类、非静态全局变量)程序文件(静态函数、静态全局变量)函数(局部变量、静态局部变量、形参)程序块(复合语句)(块内定义的局部变量),C+程序中标识符的作用域有下面几个等级:,2.名字(标识符)的生存期与作用域,外部存储属性:在所有的函数、类、名字空间外说明的标识符。静态存储属性:加以限定后使标识符的作用域限定于其所在文件中有效。如:静态全局变量、静态局部变量、静态函数。,35,5.6 程序实例,1.“三色冰激凌”程序,由冰激凌商提出的问题:有28种颜色的原料,可以组合成多少种

23、3色冰激凌。问题归结为计算排列数与组合数。,2.Hanoi塔问题,古印度的著名智力测验问题:有三个立柱A、B、C,在A柱上穿有大小不等的圆盘64个,较大的圆盘在下,较小者在上。要求借助于B柱将A柱上的64个圆盘移到C柱,规则为:,程序:p5_4.cpp,36,(1)每次只能把一个柱上最上面的圆盘移至另一个柱的最上面;(2)每个柱上总保持较大的圆盘在下,较小者在上。编制程序,实现将任意n个圆盘从A柱借助于B柱移到C柱,并显示出全部移动过程。,总任务(“度”为n的任务):把A柱上的n个圆盘,借助于B柱,按规则移到C柱上(移动规则:一次移一片,大片不可压小片)。靠调用自定义函数hanoi来完成:hanoi(n,A,B,C);,37,总任务可分解为与其等价的三个子任务(的“合集”)(“度”小于等于n-1的三个子任务):(1)把A柱上最上面n-1个圆盘,借助于C柱,按规则移到B柱上(一次递归调用);(2)把A柱上留下的(最大的)圆盘移到C柱上(一步可完成的“本原任务”);(3)把B柱上的n-1个圆盘,借助于A柱,按规则移到C柱上(又一次递归调用)。,38,靠下面的三个调用语句来完成:hanoi(n-1,A,C,B);move(A,C);hanoi(n-1,B,A,C);,程序:p5_5.cpp,

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

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


备案号:宁ICP备20000045号-2

经营许可证:宁B2-20210002

宁公网安备 64010402000987号