资源描述
1,函数在C+程序设计中的意义体现在四个方面:,(1)从历史上说,函数的思想来源于子程序,把程序中反复出现的相同或相近的程序改写成子程序,可以大大缩短程序的长度。函数实际上是参数化的子程序。,(2)从结构化程序设计(SP)的观点来看,更重要的是通过函数设计,可以把整个程序要完成的整体的复杂的计算任务,分解为一个个较小的,相对简单的子任务。这种模块化的程序易设计,易阅读,易调试,易维护,较少出错。,(3)从运算的角度说,函数就是C+语言提供的由用户定义的运算。运算符是系统提供的运算,而函数是由用户自己定义的运算。,2,(4)作为面向对象程序设计(OOP)语言的C+,以类为核心,类由数据和方法组成,方法就是对数据的运算和处理,亦即类的函数成员。故函数设计同样是OOP 的重要组成部分。,5.1 三次方程求根程序的设计,5.2 函数的说明与使用,5.2.1 函数说明,C+程序允许两种函数说明语句的形式,我们把它们分别称为函数原型(或函数声明)和函数定义。,3,1函数原型 函数原型用来指出函数的名称、类型和参数,其格式为: ();,属性说明:可缺省,一般可以是下面的关键字之一:inline,static,virtual,friend 等。 inline 表示该函数为内联函数; static 表示该函数为静态(内部)函数; virtual 表示该函数为虚函数; friend 表示该函数为某类(class)的友元函数。,4,函数原型一般在两种情形下被使用: 在程序中某函数的调用语句出现在该函数的定义之前,这时必须在调用语句之前列出函数原型。 为了类定义的简明清晰,一般把较大的函数成员定义移到类说明之外,这时应把该函数的原型列于类说明之中。,5,2函数定义 函数定义与函数原型的主要区别是它还包括函数体,其格式为: 属性说明类型函数名(参数表)函数体 属性说明,返回类型,函数名与函数原型一致,参数表中不可省略参数名。 函数体:由和括起来的复合语句即程序块。,6,5.2.2 函数调用,函数调用是已定义函数的一次实际运行,与某类型的一个变量, 某类的一个对象类似,函数调用也是函数定义的一个“实例”。 函数调用的两要素是函数名和实参表。具体的调用实施过程如下:,(1) 根据调用语句中的函数名在整个程序中搜索同名函数定义; (2) 对实参数的参数个数,类型,顺序进行核对,判定是否与函数定义中的形参表对应一致,,7,(3) 根据参数的类型(值参数或引用参数)进行值参数的值传递或引用参数的换名; (4) 运行函数体代码; (5) 返回调用点,并返回所要求的函数值。,5.2.3 函数的返回,函数的返回完成两项任务: 把运行控制从函数体返回到函数调用点。 根据返回值要求,返回所需要的数据值。,8,函数的返回值有下面几种情形: 1. 返回void 类型 如果函数无值返回,应说明为void 类型。 2返回数值类型 最常见的函数是返回一个数值的函数。 3返回引用类型 值返回方式是C 和Pascal 语言中唯一的返回方式,C+语言提供的引用返回概念是其特有的一种很强的功能,当函数定义中把该函数说明为某类型的引用类型时,该函数调用后返回的不单是值,而是包含返回值的变量(或对象)。,9,5.2.4 函数的参数,C+语言允许函数无参、有一个或多个参数,而且还支持不定个数参数的函数。,无参函数:其函数说明为下列形式: void print(void); int getx(); 用void 或空表示无参。,(2) 一个或多个参数:,(3) 不定个数参数:,有些应用问题中参数个数是变化的。处理参数个数不定的情形,可有不同的途径。,10,如:void sort(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)是第二个函数的调用。,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+语言在进行函数调用时,对参数的处理有两种方式,即值调用方式和引用调用方式。前者是普通的形式,在C 语言中只有这种方式;C+语言中增加了引用调用形式,这种形式与pascal 语言中的变量参数调用方式相似。,1 赋值调用方式(值调用方式),在函数定义的参数中,除了被说明为引用( if (n=1) f=1;else f=fac(n-1)*n; return f; ,计算4!(fac(4))的递归过程图:,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,在定义同名函数时应注意:,(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)参数名不能区分函数。 例如: int sum(int a,int b); int sum(int x,int y); (6)不要将不同功能的函数定义为重载函数,以免出现对调用结果的误解,但语法上是允许的。,27,遇到无准确匹配的函数定义时,C+系统并不马上按出错处理,它按下面的方式处理: (1)通过数组名与指针变量,函数名与函数指针,某类型变量与const 常量之间的转换,再查是否可实现匹配; (2)把实参类型从低到高(按字长由短到长)进行基本类型及其派生类型的转换,再检查是否可匹配; (3)查有无已定义的可变个数参数的函数,如有把它归为该函数。 在进行上述尝试性的处理之后可能出现仍无匹配或匹配不唯一的情况,这时可能输出出错信息或错误地运行。,28,5.4.2 运算符重载,C+语言规定,大多数运算符都可以重载,包括:,单目运算符: -,!,+,-,new,delete 双目运算符: +,-,*, (算术运算) , (位运算) (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,
展开阅读全文