第6章 过程封装--函数.ppt
《第6章 过程封装--函数.ppt》由会员分享,可在线阅读,更多相关《第6章 过程封装--函数.ppt(136页珍藏版)》请在麦多课文档分享上搜索。
1、第6章 过程封装函数,函数 自己编写函数 函数的使用 数组作为参数 带默认值的函数 内联函数,重载函数 函数模版 变量的作用域 变量的存储类别 递归函数 基于递归的算法,函数的用途,函数是程序设计语言中最重要的部分,是模块化设计的主要工具。每一个C+程序都要用到函数。 即使你自己不定义新的函数, 在每一个完整的C+程序中都必须有一个main() 函数。 在C+语言中,字符处理、字符串处理和数学计算都是用函数的方式提供的。,第6章 过程封装函数,函数 自己编写函数 函数的使用 数组作为参数 带默认值的函数 内联函数,重载函数 函数模版 变量的作用域 变量的存储类别 递归函数 基于递归的算法,如何
2、写一个函数,函数定义函数的返回值:返回值类型应与定义中的类型标识符一致。C+的函数只能有一个返回值。表示一个函数没有返回值,类型标识符用void。没有返回值的函数也称为过程,类型标识符 函数名(形式参数表) 变量定义部分语句部分 ,return 返回值; 或 return(返回值);,eg. int max(int a, int b)if (ab) return(a) else return(b); ,函数体,函数的命名,函数名是一个标识符,符合标识符命名规范 函数名要有意义 函数名一般是一个动词短语,表示函数的行为,函数举例 无参数、无返回值的函数,打印一个由五行组成的三角形,*,void
3、printstar() cout “ *n”;cout “ *n”;cout “ *n”;cout “ *n”;cout “*n”; ,函数举例 有参数、无返回值的函数,打印一个由n行组成的三角形,void printstar(int numOfLine) int i , j;for (i = 1; i = numOfLine; +i) cout endl;for (j = 1; j = numOfLine - i; +j) cout ;for (j = 1; j = 2 * i - 1; +j) cout “*”; ,函数举例 无参数、有返回值的函数,从终端获取一个1 10之间的整型数 in
4、t getInput() int num;while (true) cin num;if (num = 1 ,函数举例 有参数、有返回值的函数,计算n!,int p(int n) int s=1, i;if (n 0) return(0);for (i = 1; i = n; +i)s *= i;return(s); ,函数举例 返回布尔量的函数,判断某一年是否为润年的函数,bool IsLeapYear(int year) bool leapyear;leapyear = (year %4 = 0) ,第6章 过程封装函数,函数 自己编写函数 函数的使用 数组作为参数 带默认值的函数 内联函
5、数,重载函数 函数模版 变量的作用域 变量的存储类别 递归函数 基于递归的算法,函数的声明,所有函数在使用前必须被声明,以便让编译器知道用户的用法是否正确。 函数声明包括下列内容: 函数名 函数的参数类型 函数的返回类型 函数的声明被称为函数的原型,它的形式为:返回类型 函数名(参数表);参数表中的每个参数说明可以是类型,也可以是类型后面再接一个参数名。如:int max(int, int);int max(int a, int b);,函数说明规则,库函数在调用前需要include相应的头文件。 自定义的函数在调用时需要进行函数原型说明。 函数原型说明与函数首部写法上需要保持一致,即函数类型
6、、函数名、参数个数和参数顺序必须相同。 如果被调函数的定义在主调函数之前,可以不必加声明。 如果在所有函数定义之前,在函数外部已经做了函数声明,则在主调函数中无须再作声明。,函数调用,#include int max(int a, int b); main()int x, y;cin x y;cout b) return(a); else return(b);,函数原型说明,函数调用,函数实现,函数调用,#include int max(int a, int b) if (a b) return(a); else return(b); main()int x, y;cin x y;cout m
7、ax(x + 5, y - 3);,函数调用,函数实现,无须函数声明,建议用前一种方式!,函数调用,函数调用形式函数名(实际参数表)eg. max( x, y); 注意: 形式参数和实际参数的个数、排列次序、类型要完全相同。 实际参数可以是常量、变量、表达式,甚至是另一个函数调用 传递方式:值传递 值传递:函数获得了主调程序参数变量值的拷贝。被调程序可以改变这些拷贝,但这对主调程序的环境没有影响。,函数调用,调用方式,1. 作为语句:printstar();,2. 作为表达式的一部分,如要计算 5!+4!+7!,x=p(5) + p(4) + p(7),3. 作为函数的参数,Printstar
8、( p(5) + p(4) + p(7);,函数执行过程,在主程序中计算每个实际参数值 用实际参数值初始化形式参数 依次执行函数体的每个语句,直到遇见return语句或函数体结束 计算return后面的表达式的值,用表达式的值构造一个临时变量 回到调用函数,用临时变量置换函数调用,继续主程序的执行,函数执行过程,int p( int ); int max( int a, int b )main() int x, y;cin x y;cout n2? n1: n2); ,第6章 过程封装函数,函数 自己编写函数 函数的使用 数组作为参数 带默认值的函数 内联函数,重载函数 函数模板 变量的作用域
9、 变量的存储类别 递归函数 基于递归的算法,数组作为函数的参数,设计一函数,统计10位同学的平均成绩 设计考虑:如何传递参数 参数是10位同学的考试成绩,可以用10个整型数来表示。所以有10个整型的形式参数 一组同类数据可以用一个数组来描述,所以参数也可以是一个10个元素的整型数组 第二种方法更加简练 返回值是平均成绩,统计函数的实现,int average(int array10) int i, sum = 0;for (i = 0; i 10; +i) sum += arrayi;return sum / 10;,average函数的使用,int main() int i, score10
10、;cout scorei;cout “平均成绩是:“ average(score) endl;return 0; ,注意:形式参数是数组,实际参数也是一个数组,一个有趣的现象,在函数average的return语句前增加一个对array3赋值的语句,如array3 = 90。 在main函数的average函数调用后,即return语句前增加一个输出score3的语句 结果是什么? 你会发现输出的值90而不是80。,数组参数的传递机制,C+语言规定,数组名是数组的起始地址 参数传递时,实际参数是数组名,形式参数也是数组名 按照值传递,当用实际参数score调用函数 average时,是用sco
11、re 初始化形式参数数组array。如 score 的首地址为1000,在函数中形参数组array的首地址也为1000。 形式参数和实际参数是同一数组!,数组作为函数的参数,在函数中并没有定义新的数组 对形式参数数组指定规模是没有意义的 形式参数数组不需要指定大小,所以方括号中为空 函数如何知道数组的规模?用另一个整型参数表示 总结:数组传递需要两个参数,数组名和数组规模,第6章 过程封装函数,函数 自己编写函数 函数的使用 数组作为参数 带默认值的函数 内联函数,重载函数 函数模版 变量的作用域 变量的存储类别 递归函数 基于递归的算法,默认参数,对于某些函数,程序往往会用一些固定的值去调用
12、它.例如对于以某种数制输出整型数的函数print: void print(int value, int base); 在大多数情况下都是以十进制输出,因此base的值总是为10。 C+在定义或声明函数时可以为函数的某个参数指定默认值。当调用函数时没有为它指定实际参数时,系统自动将默认值赋给形式参数。例如,可以将print函数声明为void print(int value, int base=10);调用print(20) 等价于 print(20, 10),带有默认参数的函数的使用,C+在说明函数原型时,可以为一个或多个参数指定缺省值。调用此函数时,若缺省某一参数,C+自动以缺省值作为此参数的
13、值。如:int special(int x=2, float y=1.5)调用时可用:special(5,3.2) /x=5; y=3.2special(6) /x=6; y=1.5special( ) /x=2; y=1.5,带有默认参数的函数 注意事项,缺省参数无论有几个,都必须放在参数序列的最后,例如:Int SaveName (char *first, char second = “”,char *third = “”, char *fouth = “”); 在函数调用时,若某个参数省略,则其后的参数皆应省略而取其缺省值,带有默认参数的函数 注意事项,对参数默认值的指定只有在函数声明处
14、有意义。因为函数的默认值是提供给调用者使用的。 在不同的源文件中,可以对函数的参数指定不同的默认值。例如对于上面的print函数,如果在某一个功能模块中输出的大多是十进制数,那么在此功能对应的源文件中可以指定base的默认值为10。如果在另一个功能最模块中经常要以二进制输出,那么在此功能模块对应的源文件中可以指定默认值是2。,第6章 过程封装函数,函数 自己编写函数 函数的使用 数组作为参数 带默认值的函数 内联函数,重载函数 函数模版 变量的作用域 变量的存储类别 递归函数 基于递归的算法,内联函数,目的是为了提高执行效率。 对于任何内联函数,编译器在符号表里放入函数的声明(包括名字、参数类
15、型、返回值类型)。如果编译器没有发现内联函数存在错误,那么该函数的代码也被放入符号表里。在调用内联函数时,编译器直接用内联函数的代码替换函数调用,于是省去了函数调用的开销。,内联函数,内联函数的定义:在函数头部前加保留词inline,#includeinline float cube(float s) return s*s*s; int main() float side;cin side;cout cube(side) endls;return 0;,慎用内联函数,内联以代码复制(膨胀)为代价,省去了函数调用的开销,提高函数的执行效率。如果相比于执行函数体内代码的时间,函数调用的开销可以忽略
16、不计,那么效率的收获会很小。 以下情况不宜用内联: 如果函数体内的代码比较长,使用内联将导致内存消耗代价较高。 如果函数体内出现循环,那么执行函数体内代码的时间要比函数调用的开销大。,第6章 过程封装函数,函数 自己编写函数 函数的使用 数组作为参数 带默认值的函数 内联函数,重载函数 函数模版 变量的作用域 变量的存储类别 递归函数 基于递归的算法,重载函数,在传统的C语言中,不允许出现同名函数。当要求写一组功能类似、参数类型或参数个数不同的函数时,必须给它们取不同的函数名 例如某个程序要求找出一组数据中的最大值,这组数据最多有5个数据。我们必须写四个函数:求两个值中的最大值、求三个值中的最
17、大值、求四个值中的最大值和求五个值中的最大值。我们必须为这四个函数取四个不同的函数名,例如:max2, max3, max4和max5。,函数重载,使参数个数不同、参数类型不同或两者兼而有之的两个以上的函数取相同的函数名 如 int max(int a1, int a2); int max(int a1, int a2, int a3); int max(int a1, int a2, int a3, int a4); int max(int a1, int a2, int a3, int a4, int a5);,函数重载的实现,由编译器确定某一次函数调用到底是调用了哪一个具体的函数。这个过
18、程称之为绑定(binding,又称为联编或捆绑)。 编译器首先会为这一组重载函数中的每个函数取一个不同的内部名字。当发生函数调用时,编译器根据实际参数和形式参数的匹配情况确定具体调用的是那个函数,将这个函数的内部函数名取代重载的函数名。,第6章 过程封装函数,函数 自己编写函数 函数的使用 数组作为参数 带默认值的函数 内联函数,重载函数 函数模版 变量的作用域 变量的存储类别 递归函数 基于递归的算法,函数模板,如果一组重载函数仅仅是参数的类型不一样,程序的逻辑完全一样,那么这一组重载函数可以写成一个函数模板。 所谓的函数模板就是实现类型的参数化(泛型化),即把函数中某些形式参数的类型定义成
19、参数,称为模板参数 在函数调用时,编译器根据实际参数的类型确定模板参数的值,生成不同的模板函数。,函数模板的定义,一 般的定义形式template返回类型 FunctionName(形式参数表)/函数定义体 模板形式参数表可以包含基本数据类型,也可以包含类类型(需加前缀class)templateT max(T a, T b) return ab ? a : b;,函数模板的使用,maxNum = max(3, 7); maxChar = max(z, a); maxDouble = max(3.5, 4.6); 函数模板的实例化: 根据实际参数确定模板参数的值 将模板参数的值代入函数模板,形
20、成一个真正的函数,第6章 过程封装函数,函数 自己编写函数 函数的使用 数组作为参数 带默认值的函数 内联函数,重载函数 函数模版 变量的作用域 变量的存储类别 递归函数 基于递归的算法,标识符的作用域,一个标识符能被存取的程序部分,称为标识符的作用域 标识符的作用域与程序块有关。所谓的程序块是带有声明的复合语句 如右框中有两块,Int main(void) int a = 2, b = 3;cout a b; int a = 4;cout a b;cout a b; ,标识符的作用域续,在块中说明的标识符是局部的,仅能在本块中和内部的块中存取。 当内部块与外部块有同名标识符时,在内部块中屏蔽
21、外部块的同名标识符。 在一个函数中,我们不能存取主调程序的变量,即使知道该变量的名字。 函数参数对该函数也是局部的,可以将它看成在块内,即函数体内说明的说明的变量。,局部变量和全局变量,局部变量:在块内定义的变量称为局部变量,即使是main函数中定义的变量也是局部的。 全局变量:在所有的函数外面定义的变量称为全局变量 作用范围:从定义位置到文件结束。如在作用范围外的函数要使用此变量,用关键词extern在函数内说明此全局变量。 作用:方便函数间的数据传递 请写出下列程序的执行结果:,int p = 1, q = 5, r=3; int f1()int p = 3, r = 2;q=p+q+r;
22、 cout “f1: p,q,r=“ p q r; int f2()p=p+q+r; cout “f2: p,q,r=“ p q r; int f3()int q; r = 2*r; q=r+p;cout “f3: p,q,r=“ p q r; main() f3(); cout “after f3: p,q,r=” p q r;f1(); cout “after f1: p,q,r=“ p q r;f2(); cout “after f2: p,q,r=” p q r; ,结果:,f3: p,q,r=1 7 6,after f3: p,q,r=1 5 6,f1: p,q,r=3 10 2,a
23、fter f1:p,q,r=1 10 6,f2: p,q,r=17 10 6,after f2: p,q,r=17 10 6,全局变量的使用说明,全局变量破坏了模块化,建议尽量少使用 当全局变量和局部变量同名时,在局部变量的作用范围中全局变量被屏蔽。 全局变量的使用将在模块化设计中详细介绍,第6章 过程封装函数,函数 自己编写函数 函数的使用 数组作为参数 带默认值的函数 内联函数,重载函数 函数模版 变量的作用域 变量的存储类别 递归函数 基于递归的算法,存储类型,在C+语言中,每个变量有两个属性: 类型:变量所存储的数据类型 存储类型:变量所存储的区域: 标准的变量定义: 存储类型 数据类
24、型 变量名; 存储类型: 自动变量:auto 寄存器变量:register 外部变量:extern 静态变量:static,auto,在函数内或块内定义的变量缺省时是auto。如 auto int i; 当进入块时,系统为自动变量分配空间。当退出块时,系统释放分配给自动变量的值。因此自动变量的值就消失了。当再次进入该块时,系统重新分配空间。,register,存储在寄存器中,代替自动变量或形参,可以提高变量的访问速度。 如无合适的寄存器可用,则编译器把它设为自动变量。,extern,声明一个不在本模块作用范围内的全局变量。如:extern int num;num为一个的全局变量。 用途: 在某
- 1.请仔细阅读文档,确保文档完整性,对于不预览、不比对内容而直接下载带来的问题本站不予受理。
- 2.下载的文档,不会出现我们的网址水印。
- 3、该文档所得收入(下载+内容+预览)归上传者、原创作者;如果您是本文档原作者,请点此认领!既往收益都归您。
下载文档到电脑,查找使用更方便
2000 积分 0人已下载
下载 | 加入VIP,交流精品资源 |
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 过程 封装 函数 PPT
