第五章成员函数.ppt

上传人:本田雅阁 文档编号:3118387 上传时间:2019-07-12 格式:PPT 页数:77 大小:318.03KB
返回 下载 相关 举报
第五章成员函数.ppt_第1页
第1页 / 共77页
第五章成员函数.ppt_第2页
第2页 / 共77页
第五章成员函数.ppt_第3页
第3页 / 共77页
第五章成员函数.ppt_第4页
第4页 / 共77页
第五章成员函数.ppt_第5页
第5页 / 共77页
点击查看更多>>
资源描述

《第五章成员函数.ppt》由会员分享,可在线阅读,更多相关《第五章成员函数.ppt(77页珍藏版)》请在三一文库上搜索。

1、第五章 成员函数,5.1 成员函数的概念,为了实现对象的行为,我们把一些相关的语句 组织在一起,并给它们注明相应的名称,形成一 些相对独立而且便于管理和阅读的小块程序,每 个小程序块描述了一个完整的行为,这种形式的 组合就构成了成员函数。,5.2.1 算法的概念,一个完整的对象应该包括两个方面的内容, 即对数据的描述(对象属性)和对操作的描述 (对象行为)。对操作的描述也就是算法,是设 计和实现对象行为的灵魂。 一个完整的算法应该具有以下5个特性: 有穷性、确定性、有效性、输入性和输出性。,5.2.1 算法的表示,为了表示一个算法,可以采用多种形式。最常见的几 种方法有自然语言表示法、流程图表

2、示法、伪代码表示法 和计算机语言表示法。 自然语言表示法: 自然语言表示法就是用我们日常生活中的语言来表示算法的实现 过程,对采用何种语言没有限制。但是采用自然语言表示往往不太严 格,容易造成歧义。另外,用这种方法描述包含分支和循环的算法不 太方便。因此,自然语言表示法很少用来描述复杂的算法。 流程图表示法: 流程图就是用一些图框表示各种操作。用流程图来表示算法最大 的优点就是直观形象,便于理解,并且实用性强,能够方便的表示包 含分支和循环的结构,避免了用自然语言表示算法的不足。,图5.1 一般流程图表示算法,图5.2 N-S流程图表示算法,5.2.2 算法的表示,伪代码表示法: 伪代码是用介

3、于自然语言和计算机语言之间的文字和符号来描述算法。从结构上看,伪代码表示法类似于最终的计算机语言,每一行就表示一个基本的操作。 伪代码表示法书写格式比较自由,容易直观表达出设计者的思想。同时,书写的算法也容易修改,很容易写出结构话的算法。 因此,这种方法一般被专业的软件开发人员采用,特别是在详细 设计中采用伪代码表示法,可以使以后的编码阶段变得简单。,5.2.2 算法的表示,计算机语言表示法: 一个算法要拿到计算机上去运行,最终还是要采用计算机语言表示。目前使用的计算机语言多种多样,本书所介绍的面向对象的程序设计语言(C+)就是种很好的描述和实现算法的工具。,5.3 成员函数的定义与调用 5.

4、3.1 成员函数的定义,说明一个函数原型的一般形式有两种: 返回值类型 函数名(参数类型1 参数名1,参数类型2 参数名,); 返回值类型 函数名(参数类型1,参数类型2,);,5.3.1 成员函数的定义,定义一个成员函数必须具备四个条件: 函数必须具有返回值类型,即函数必须有返回值,且该 返回值的类型应该与函数返回值的类型一致 函数必须具有一个名字,即函数名。 函数必须具有一个形参(形式参数)列表,C+规定, 形参列表以左括号“(”开始,到右括号“)”结束,且各个形参 之间用“,”分开。 函数要完成一定的功能,必须具有一个函数体,其中,前面的三个条件构成了函数的原型。,说明一个函数原型的一般

5、形式有两种: 函数返回值类型 函数名(参数类型1 参数名1, 参数类型2 参数名2, ); 函数返回值类型 函数名(参数类型1, 参数类型2 , ); 以上两种方法均可以使用,但是为了增加程序的可读性建 议使用第一种方法。 请注意,这时的函数名应该包含: 类名(Circle)+ 作用域分辨符(:)+ 原函数(circle_area),5.3.1 成员函数的定义,5.3.2 成员函数的调用,一般形式有两种: 对象名.函数名(实参1,实参2,); 对象指针函数名(实参1,实参2,); 例如: void main() cout “The area of circle = ” mycircle.cir

6、cle_area(3.14); ,5.3.2 成员函数的调用,关于形参和实参的说明: 在函数定义时说明的形参,并不占内存中的存储单元。 只有在函数调用时,形参才被分配内存单元,并被赋以实 参的值。在调用结束后,该部分内存立刻被释放。 实参可以是常量、变量、或表达式等,但要求它们必须 有确定的值。,5.3.3.1函数指针,在程序运行中,每个函数在编译时都会被编译 器分配给一个入口地址,则指向这个入口地址的 指针就称为函数指针。函数代码是程序的算法指 令部分,被存放在代码区(code),函数指针指 向代码区中某个函数的地址,因此,通过函数指 针可以调用相应的函数。,函数指针的声明 正确的指针类型声

7、明如下: 返回值类型 (*函数指针名)(参数表); 例如:int ( * func_p)(char a , char b); 其中,“int”表示函数的返回值类型为整型,“(*func_p)” 表示func_p是一个指针,后面的(char a,char b)表示该指针(func_p)是函数指针。其定义后产生的指针变量有全局、静态与局部之分,同样占有内存空间(与其他类型指针变量所占空间相同)。,5.3.3.1函数指针,5.3.3.1函数指针调用函数,由于(*func_p)所扮演的角色与函数名相同,因此在使 用(*func_p)时,只需将他看作函数名即可。 看下面一个例子,学习如何通过函数指针调用

8、函数: int func(int); int (*func_p)(int); func_p=func; /函数指针(*func_p)指向代码区函数func()的地址 int x = func (4);/使用函数func(),这个用法很常见 int y = (*func_p)(5); /使用函数指针(*func_p)实际上调用了func()函数,5.3.3.1函数指针用作函数参数,函数指针可以作为函数的参数,如下所示: int all(int x,int y,int(*func)(int ,int) return(*func)(x,y); 函数all共有3 个形参,它的第三个形参是指向函数的指针

9、对象int(*func)(int ,int) ,可用一个定义的函数代替all中的 func,例如all(a,b,max),相当于执行max(a,b),从而输出 a,b当中的最大值。 同样方法可以调用 min,而all函数的形式不变,只是在调用时改变实参函数名。这就增加了函数使用的灵活性,它在大型程序设计中,尤其是模块设计时特别有用。,完整的示例程序:,#include using namespace std; int all(int x,int y,int(*func)(int ,int) return(*func)(x,y); int max(int x,int y) return(xy?x

10、:y); int min(int x,int y) return(xy?x:y); void main() int a,b; a=15,b=20; cout“max=“all(a,b,max)endl; cout“min=“all(a,b,min)endl; ,5.3.3.1函数指针注意事项,注意: (1)定义一个函数指针与定义一个返回值是指针的函数不同 int(*f_p)(const char*); / 定义一个函数的指针 int *func_p(char a )/ 定义一个返回指针的函数 (2)可以用typedef简化函数指针的使用,如下例: typedef int(*FUN)(int a

11、, int b); /声明(*FUN)是一个函数指针类型 FUN func_p; /func_p为一个返回整型和两个整型参数的函数指针 (3)函数指针可以和其他指针一样地使用,5.3.4内联函数,内联函数也称内嵌函数,它主要是解决程序的运行效率。 因为函数调用通常需要建立栈内环境,进行参数传递,并产生程序执行转移,这些工作都需要一些时间开销,对于一些代码很短,但使用频率很高的函数来说,时间开销显得尤为突出。 如果将那些代码很短且调用频率高的函数定义为内联函数,则编译器在程序中每次遇到该函数名时,都直接用内联函数的函数体来替换,以次来减少时间开销。,#include using namespac

12、e std; inline int isnumber(char); / inline 函数声明 void main( ) char c; while(c=cin.get()!=n) if(isnumber(c) / 调用一个小函数 cout=0 ,下面的代码表达了一个内联函数:,5.3.4内联函数,注意: (1)内联函数体内不允许使用循环语句和开关语句(这两种语句的介绍见5.4节); (2)内联函数的定义必须出现在内联函数第一次调用之前; (3)所有在类定义体内部定义的函数都是内联函数; (4)递归函数是不能被用来做内联函数的。 (5)内联函数只适合于15行的小函数。,5.4 运算符和表达式

13、5.4.1 运算符及运算符优先级,像代数中一样,C+中的运算符是连接参加 运算的数据的符号,不同的运算符规定了不同的 运算方法和不同的运算规则(如先乘除后加减) C+语言的运算符,基本上可以分为以下几 种类型。见下表5.1所示。,5.4.2 表达式,所谓表达式是指:用运算符将运算对象(也称操作数) 连接起来的、符合语法规则的式子。 根据连接运算对象的连接符(运算符)的不同大体上可以将 表达式分为以下四种: 算术运算表达式(算术运算表达式的运算结果是数值 ) 逻辑运算表达式(逻辑运算表达式的运算结果是逻辑值 ) 赋值运算表达式(赋值运算符的结合性是从右向左的 ) 逗号运算表达式(逗号运算表达式的

14、值是最后一个表达式 的值 ),5.4.2 表达式,注意: 当一个表达式中包含多种运算符时,必须考虑运算符的优先级和 结合性。 可以用()改变运算符的优先级; 例如: int i = 1,n = 2; n = i + n 1; / 因为 “+” 高于 “” 高于 “=”,所以先运算i+n 等于3, /再运算31得6,最后n = 6。 用“()”改变先后次序如下: int i = 1,n = 2; n = i + (n 1); / 因为 (n1) 高于 “+” 高于 “=”,所以先运算n1 等 /于4,再将4 + 1得5,最后n = 5。,5.4.2 表达式,只要符合表达式定义的式子,都是表达式,

15、不 一定非要包含赋值运算符,如下面的式子都是正 确的C+表达式: 3 + 5; a, b, c; x y ? e1 : e2; i + ; 赋值运算符左侧必须是一个可以引用的存储单 元(如:变量),决不能是表达式。,5.4.3 数据类型的转换,类型转换就是将一种类型的值转换为另一种类型的值。 隐式类型转换 其转换过程是由系统按照一定的转换规则自动完成的。 显式类型转换 显式类型转换的方法有两种。 (1) 强制转换法 强制转换法的格式为:(类型名)表达式; 如:(int)x; (2) 函数法 函数法的转换格式为:类型名(表达式); 如: int(x );,为了提高程序的设计质量,1966年,Bo

16、hm和 acopini提出了在程序设计过程中,使用以下三种控制结构作为算法的基本单元。事实上,任何一个成员函数的定义都离不开这三种基本结构: 5.5.1 顺序结构 顺序结构是指程序语句按顺序,自上而下依次执行 5.5.2 选择结构(又称分支结构) 选择结构是指能根据选择条件,改变程序走向的一种语句 5.5.3 循环结构 循环结构是指能根据循环条件,重复执行某段程序的一种语句。是代码可重用技术的一种基本形式,5.5 控制结构,5.5.1 顺序结构,顺序结构是指程序语句按顺序,自上而下依次执行。 如,输入三角形的三边长,求三角形面积的函数。f_area: float f_area( float a

17、, float b, float c ) float s; s = 1.0 / 2 * ( a + b + c ); return sqrt ( s * (s a ) * ( s - b ) * ( s - c) ); ,5.5.2 选择结构(又称分支结构), if 和 if else if是最简单的选择语句,一般格式为: if() 当条件表达式的值为“真”,我们所要执行的语句多于一条时,C+ 规定,必须将这些语句用“”和“”括起来。一般格式为: if() ,5.5.2 选择结构(又称分支结构),if else是用来解决在互相对立的两种条件下,所要分别进行处理 的两条语句。 if() else

18、 ,5.5.2 选择结构,当分支结构(即选择结构)的分支较多时,C+提供了嵌套式的选择结构:,if() else if() else ,5.5.2 选择结构(又称分支结构),例如,设计一个函数,当输入大于0时,输出为1;当输入小于0 时,输出为 -1;当输入等于0时,输出为0;(注意本例中判断条件有 三种情况) int f_s(int x) if(x0) /到此排除了x0和x = 0的情况 x = 1; else /到此排除了x0的情况,只剩下x = 0的情况 x = 0; return x; ,5.5.2 选择结构(又称分支结构),switch语句又称开关语句。主要用于根据某个整型数据的变

19、化,达到多种分支的目的。一般格式为: switch(整型表达式E) case 整型表达式E1: 语句系列1; break; /跳过下面的所有语句直接去执行语句k+2; case 整型表达式E2: 语句系列2; break; case 整型表达式Ek: 语句系列k; break; default: 语句系列k + 1; /开关语句结束 语句k + 2; ,5.5.2 选择结构(又称分支结构),注意: 整型表达式E,E1,E2,Ek的值,是整型数据(或者 字符变量、字符常量)。 当整型表达式E的值等于整型表达式E1的值时,执行语句 系列1;同理当整型表达式E的值等于整型表达式Ek的值时, 执行语句

20、系列k。 当程序执行到break时,将跳过下面所有的语句,执行开 关语句后的语句,即语句k+2。 当整型表达式E的值不等于整型表达式E1,E2,Ek的 值时,则执行default语句下的语句系列k+1。,5.5.2 选择结构(又称分支结构),例如,编程实现两个浮点数的四则运算函数f_arith: float f_arith(float d1, float d2, char op ) float temp; switch(op) case +: temp = d1 + d2; break; /跳过下面的所有语句直接去执行switch语句后面的语句 case -: temp = d1 - d2;

21、break; case *: temp = d1 * d2; break; case /: temp = d1 / d2; break; default: temp = -100; /开关语句结束 return temp; /函数结束,5.5.3 循环结构,for语句 当参加循环的语句(又称循环体),只有一条语句时,其一般格式为: for( E1; E2; E3 ) 例如:计算从1到n的自然数的累加和函数f_sum。 int f_sum( int n) int i, sum = 0; for( i = 1; i n + 1; i + ) sum += i; return sum; ,5.5.3

22、 循环结构,当参加循环的语句,多于一条语句时,需要用 “”和“”将循环体括起来。其一般格式为: for( E1; E2; E3 ) ,5.5.3 循环结构,break语句与continue语句对循环的影响 break语句: 当某个条件满足,我们想结束循环时,采用这个语句。 其一般形式为: for( ) if(条件表达式E) break ; /离开整个循环直接跳到循环体外,执行 . ,5.5.3 循环结构,continue语句: 当某个条件满足,我们并不想结束循环,只想跳过某些循环语句 时,采用这个语句。其一般形式为: for( ) /循环起点 if(条件表达式E) continue ; /跳过

23、,重返循环起点 /循环终点 ,5.5.3 循环结构,计算 n, n+k 范围内的自然数中偶数的累加和(其中n和k均为自然数) int f_psum( int n, int k ) int sum = 0; while( n0 ) / 确保n是自然数才计算 if( k0 ) /结束计算的条件,即跳出循环 break; if( (n+k-)%2 != 0 ) / 奇数不累加,即跳过下面的语句重返循环起点 continue; sum += k + 1 + n ; return sum; ,5.5.3 循环结构,多重循环。在某个循环语句内还包含另一个循环语句。C+中称为 多重循环(或循环嵌套)。其一般

24、格式为: for( E1; E2; E3 ) /外循环语句起点 / 外循环体语句系列 for( E11; E22; E33 ) /内循环语句起点 / 内循环体语句系列 /内循环语句终点 /外循环语句终点,5.5.3 循环结构, while语句一般格式为: while( ) ,5.5.3 循环结构, dowhile语句一般格式为: do while( );,5.5.3 循环结构,注意: 循环语句的形式比较多,要根据需要合理选用。 while和dowhile型循环语句,同样可以实现多层嵌。 break和continue语句均可使用于while和dowhile语句,但 是,它们仅作用于本层循环上,在

25、任何一层上要实现break和 continue的操作,都必须在这一层中增加这两条语句。 在书写时,不要忘记dowhile语句中最后的“;” 。 建议养成良好的编程习惯,不要在循环体内说明数据 成员或者函数的原型,如:int num; 或者char* func( int a, char* s ); 类似的声明应在循环体外。,5.5.4 递归函数的自我调用,所谓“递归”是指通过重复执行相同的计算来解决问题。 简单的说,递归就是函数直接或间接地自己调用自己。从而 使得程序简短。编写递归程序的关键是: 构造递归表达式。将n阶的问题转化为比n阶小的问题,转化以后的问题与原来的问题的解法是相同的。 (2)

26、 必须寻找一个明确的递归结束条件,称为递归出口。 递归是在函数中出现调用函数本身的语句,只是每次调用时函数的实参值不一样,如果代码中没有包含终止调用的控制语句,将无限循环下去。因此,通常用if语句中条件的判断来决定是否跳出这个递归过程。,#include #include int f(int x) int y; if(x=0|x=1) return 3; y = x - f(x-2); return y; void main() cout “f(5)=” f(5) endl; cout “f(6)=” f(6) endl; cout “f(8)=” f(8) endl; ,运行结果为: f(5

27、) = 5 f(6) = 1 f(8 )= 7,请看下面一个例子:,5.5.4 递归函数的自我调用,图5.3 递归示意图,5.5.4 递归函数的自我调用,程序详解: 函数从main()开始执行,f(5)为第一轮调用,实参5被代入f(int x), 即f(5)。函数内判断是否该返回(这是递归函数中必须要有的语句) “if(x=0|x=1) return 3;”之后,函数开始调用自己(这也是递归函数 中必须要有的语句,否则不称为递归调用) y = x - f(x-2);(即:y=5-f(3)) f(3)为第二轮调用,将实参3代入f(int x),即f(3)。函数内判断是否该返回“if(x=0|x=

28、1) return 3;”之后,函数开始调用自己 y = x - f(x-2);即y=3-f(1);,5.5.4 递归函数的自我调用,程序详解: f(1)为第三轮调用,将实参1代入“f(int x)”,即:“f(1)”。函数内判断 是否该返回“if(x=0|x=1) return 3;”之后,即f(1)= 3。 因此:f(5)=5-f(3)=5-(3-f(1) ) = 5-(3-3) = 5 同理:f(6) = 6-f(4)=6-(4-f(2)=6-(4-(2-f(0) =6-(4-(2-3) = 6-5=1 类推:f(8)=8-f(6)=8-1=7 注意:不要忘记语句“return y;”,

29、5.5.4 递归函数的自我调用,5.5.4 递归注意事项,注意: 使用递归编写程序虽然代码较少,但程序的可读性较差。 使用递归时层次不能太深,一般不超过3层。多层函数递 归将造成系统资源的严重浪费。 由于递归的缺点很明显,所以在实际开发工作中不建议 使用递归。,5. 6函数的参数的传递机制,当一个函数定义有形参时,在进行函数调用时,必须 提供与形参个数相同、顺序相同、类型相同的实参;或 通过类型转换能够将实参的值映射为形参类型的值。 在C中,可以使用两种传递机制将实参的值传递 给形参: 一种被称为值传递 (值调用)。 另一种被称为引用传递(引用调用)。,5.6.1传值调用,C+中变量的值有两种

30、:变量本身值和变量地址值。 1. 传值调用的特点: 调用时系统先计算实参表达式的值,然后依次赋给形参。因此,传值调用的实现机制是系统将实参拷贝一个副本给形参。在被调用的函数中参数(即参数的副本)被改变,但未改变实参的值(即不能“回带” )。 例如:交换两个变量a和 b的值(采用传值调用)。 void f_swap1( int A, int B ) int temp; temp = A; A = B; B = temp; cout “A=”A” “”B=”Bendl; ,void main() int a = 5, b=6; f_swap1( a, b ); /执行完该语句后,变量的值没有改变

31、cout “a=”a“ ”“b=”bendl; 运行结果如下: A=6 B=5 /函数内的结果 a=5 b=6 /主函数中的结果,可见通过传值调用a、b的 /值并没有被“回带”,5.6.1传值调用,5.6.1传值调用,2.传址调用的特点 使用传址调用方式时,调用函数的实参是某个变量的地址值,被 调用的函数的形参是指针(变量的指针或类类型的变量的指针)。千万注意,不能通过return返回或者通过参数“回带”,在函数中 定义的局部变量的地址(或指针)。 例如,通过函数返回、指针参数和引用参数来得到函数中局部变量的 值。下面的做法结果是错误的: int* f_pIntandInt(int * y,

32、int ,void main() int a = 6,b = 7; int *pa = 运行结果如下: *x=351 / *x不是5而是个随机数 *pa=6 /*pa也不是5且未被修改 b=5 /“回带”了值5,5.6.1传值调用,5.6.2引用调用,使用引用作为函数的形参时,调用函数的实参要 用变量名,将实参的变量名传给形参的引用,相当于 在被调用函数中使用了实参的别名。 例如:交换两个变量a和 b的值。(采用引用调用) void f_swap3( int ,void main() int a = 5, b=6; f_swap3( a, b );/变量的地址没变,但是变量的值被间接改变 co

33、ut “a=”a” “”b=”bendl; 运行结果如下: A=6 B=5 /函数内的结果 a=6 b=5 /主函数中的结果,可见引用调用a、b的值被“回带” 建议:在需要“回带”值的时候,使用引用。,5.6.2引用调用,5.7 函数的参数 5.7.1 函数参数的求值顺序,当一个函数带有多个参数时,C语言没有规定在函 数调用时对实参的求值的顺序,编译器根据对代码进行优 化的需要自行决定对实参的求值顺序。有的编译器规定自 左向右,有的编译器规定自右向左,这种求值顺序的不 同,对一般参数来讲没有影响。但是,如果实参表达式中 的某个变量与前后表达式中的某个变量有关时,就可能由 于求值顺序的不同而造成

34、了二义性。因此,建议将参数列 表简单化为好(相关运算放在调用前)。(举例如下),int f_add_int( int x, int y, int z ) return x + y + z; void main() int x=5, y=6, z=7,c; c = f_add_int( +x, x+y+z, -z ); 如果编译器规定自左向右的求值,则 c = f_add_int( 6, 6+6+7, 6 ), c=31; 如果编译器规定自右向左的求值,则 c = f_add_int( 6, 5+6+6, 6 ), c=29;,5.7.1 函数参数的求值顺序,5.7.2数组作为函数参数,数组作为

35、函数参数时,根据调用机制的不同,可以分为两种情况: 形参用数组实参用数组名 调用函数的实参用数组名,被调用的函数的形参用数组,这种调用的机制是形参和实参共用内存中的同一个数组。 例如:检查数组Am,将数组中小于0的数改写为0; void f_rw1( int A , int n ) /定义时形参要标明数组元素的类型、数组名、数组维数 for(int i=0;in;i+) if(A i 0 ) A i = 0; ,void main() int a4 = 1, -5, 4, -3 ; int n = 4; f_rw1( a, 4); /调用时实参只写数组名 结果是a中的元素变为:1,0,4,0,

36、5.7.2数组作为函数参数,5.7.2数组作为函数参数,形参用指针实参用数组名 调用函数的实参用数组名,被调用的函数的形参用指针,这种调用的机制是实参把数组的名字传递给形参。 例如:检查数组Am,将数组中小于0的数改写为0; void f_rw2( int *A, int n ) /形参用指针 for(int i=0;in;i+) if( *( A + i ) 0 ) *( A + i )= 0; void main() int a4 = 1, -5, 4, -3 ; int n = 4; f_rw2( a, 4); /调用时实参只写数组名 ,5.7.3带缺省值的函数,C+语言允许在函数的原型

37、中(若没有说明函数的原型,则应在函数定义时),给一个或多个参数指定默认值。但是,在指定了默认值的参数右边不能出现没有指定默认值的参数。 正确的带缺省值函数的原型是: void f_a ( int x, int y=8, int z = 9) ; 错误的带缺省值函数的原型是: void f_a ( int x=5, int y, int z=6 ) ; void f_a ( int x=5, int y=6, int z ) ;,5.7.3带缺省值的函数,C+不允许在函数原型和函数定义中,同时指定默认值。如: void point(int =3,int=4); / 声明中给出默认值 void p

38、oint(int x,int y) /定义中不允许再给出默认值 coutxendl; coutyendl; ,5.7.3带缺省值的函数,在函数调用时,编译器按从左到右的顺序将实参传给形参,当实参的数目不足时,编译器将按同样的顺序用函数定义中的默认值来补充所缺少的实参。如函数声明为: void func(int a,int b=2,int c=3,int d=4); 其调用的方法规定为: func(10,15,20,30); /正确,调用时给出所有实参 func(12,12); /正确,参数c和d默认 func( ); /错误,参数a没有默认值 func(2,15, , 20); /错误,只能从

39、右到左顺序匹配默认,5.9 函数的重载,所谓函数重载是指相同的函数名下,可以实现不同的操 作。系统将根据参数类型或者参数个数的不同来区分这些重 载的函数。用户在调用时,只要给出不同类型的参数或者不 同个数的参数。编译器就能区别你要调用哪个函数。 函数重载的两个条件: 函数名相同; 函数参数的类型不同或者参数的个数不同 。,5.9 函数的重载,#include using namespace std; double f_add(double x,double y )return x+y; int f_add(int x,int y ) return x+y; int f_add(int x,in

40、t y,int z) return x+y+z ; void main() cout“f_add(7.8,5.9)=“f_add(7.8,5.9)endl; cout“f_add(4,7)=“f_add(4,7)endl; cout“f_add(5,7,3)=“f_add(5,7,3)endl; ,运行结果: f_add(7.8,5.9)=13.7 f_add(4,7)=11 f_add(5,7,3)=15,重载时应该注意的问题 :,如果仅仅是函数的返回类型不同,是不能作为函数重载的条件的。 例如,下面的声明是错误的: int func(char ,int ); void func(char,

41、int); 当参数类型及个数一致时,编译器无法区分函数调用调用上述哪一个函数,因此重载函数至少在参数个数,参数类型或参数顺序上有所不同。,重载时应该注意的问题 :,2.在函数调用时,如果给出的实参和形参类型不相符,C+的编译器会自动做类型转换工作,如果转换成功,则程序继续执行,在这种情况下,有可能产生不可识别错误。例如有两个函数的原型如下: void f_a (int x); void f_a (long x); 虽然这两个函数满足重载的条件,但是如果用f_a(5.56)调用,就会出现“不可分辨”错误,因为编译器无法确定将5.56转换成int型还是long型。,3.当形参中有引用类型时也要格外

42、小心。 例如有两个函数的原型如下: void f_a ( int x ); void f_a ( int 如果用f_b(5)来调用的话,也会出现“不可分辨”错误,因为在实参的使用上,引用变量和普通变量是一样的,编译器无法确定该使用哪个函数。,重载时应该注意的问题 :,重载时应该注意的问题 :,4.当形参中带有缺省值时也要格外小心。 例如有两个函数的原型如下: void f_a ( int x ,int y=6); void f_a ( int x ); 如果用f_a( 9 )调用上面任何一个函数都会出现“不可识别”错误。,5.11 用计算机求解智力游戏,以下通过一个有趣的例子加深读者对函数及算

43、法的理解: 题目如下: 一棵树上来了一群鸟,一个鸟落一个树枝多了一个 鸟,如果两个鸟落在一个树枝上多了一个树枝,问有几个 树枝几个鸟?试编写程序,并输出结果。 算法分析: 依题意可知,设有x个鸟,y个树枝,因为“一个鸟落一 个树枝多了一个鸟”所以,x y = 1;因为“如果两个鸟落在 一个树枝上多了一个树枝”所以,y x / 2 = 1。本例通过对 y从1开始取值,使用循环语句对y进行穷举,直到满足y x / 2 = 1式成立为止(可见,树枝的数必是奇数)。,5.11 用计算机求解智力游戏,#include using namespace std; void main() int x = 2,y = 1; do x = y + 1; /式x y = 1的变形 if(y - 1)*2 = x) /式y - x. / 2 = 1的变形 break; while(y+); cout“x=“xendl; cout“y=“yendl; ,运行结果是: x=4 y=3,

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

当前位置:首页 > 其他


经营许可证编号:宁ICP备18001539号-1