《面向对象程序设计第五章函数.ppt》由会员分享,可在线阅读,更多相关《面向对象程序设计第五章函数.ppt(43页珍藏版)》请在三一办公上搜索。
1、第五章 函数,函数概述,函数的说明与使用,5.2 函数的说明与使用,五、函数参数传递,1.传值调用方式,例,int mul(int m)m=m*3;return m;,调用函数2次:,int m=5;/变量与形参同名cout mul(2)mul(m)mendl;,执行结果:,6 15 5,传值调用是指在发生函数调用时,先计算实参表达式的值,并直接将各实参的值依次赋值给各形参。单向传递,即由实参到形参;形参的值不能影响实参的值。,#includeint add(int,int);void main()int a,b,c;cin a b;c=add(a,b);cout c=c endl;int a
2、dd(int i,int j)i+;j+;return(i+j);,a,b,输出,c=8,5.2 函数的说明与使用,五、函数参数传递,2.引用调用方式,5.2 函数的说明与使用,五、函数参数传递,2.引用调用方式,说明:,引用在定义时一定要初始化,例,int a=3;int,对引用的操作就是对被引用 的变量的操作,可以把某个引用赋给一个变 量,该变量的值就是被引用 的变量值,引用一旦初始化后不得作为 其他变量的别名,5.2 函数的说明与使用,五、函数参数传递,在一条语句中声明多个引用:,int,注,int,int,#include void main()int x=3,5.2 函数的说明与使用
3、,五、函数参数传递,2.引用调用方式,例,5.2 函数的说明与使用,五、函数参数传递,2.引用调用方式,函数的引用调用:,调用函数的实参必须要用变量名,将实参变量名赋给形参的引用,相当于在被调用函数中使用了实参的别名。如swap(a,b);,在函数原型中该参数类型后面加上&,如:,void swap(int,5.2 函数的说明与使用,五、函数参数传递,2.引用调用方式,函数的引用调用:,相比按值调用,按引用调用对性能有利,因为它消除了复制大量数据的开销。但按引用调用的安全性较差,因为被调用函数能够直接访问和修改调用者的数据。,#include void swap(int x,int y)int
4、 temp=x;x=y;y=temp;coutx“”yendl;void main()int a=3,b=5;swap(a,b);couta“”bendl;,#include void swap(int,在传值调用中,swap()函数中形参值的改变对实参无影响,在引用调用中,有&x=a,&y=b,因此x和a,y和b同时改变,从而达到实参交换的目的,输出结果:5 3 3 5,输出结果:5 3 5 3,#include int squareByValue(int);void squareByReference(int,x=2 before squareByValue,Value returned
5、by squareByValue:4,x=2 after squareByValue,z=4 before squareByReference,z=16 after squareByReference,5.2 函数的说明与使用,五、函数参数传递,3.传地址调用方式,*指针运算符,表示指针所指向变量的值 int*p,&取地址运算符,用于得到一个对象的地址&i,int a;int*ptr;ptr=/将变量a的地址赋值给指针ptr,#include void swap(int*,int*);void main()int a=3,b=8;cout a=a,b=b endl;swap(,5.2 函数的说
6、明与使用,五、函数参数传递,传址调用指将实参的地址传递给形参采用这种方式调用时,实参必须用地址值,形参用指针变量发生函数调用时,将实参地址直接传递给相应的各形参指针变量在函数中通过形参指针可以对实参进行间接读写,5.2 函数的说明与使用,五、函数参数传递,3.传地址调用方式,5.2 函数的说明与使用,六、函数的嵌套与递归,函数嵌套:一个函数的函数体中包含一个或多 个函数调用语句。,若函数A要调用函数B,则函数B的定义 或函数原型必须出现在A的定义之前。,说明,若函数A在执行过程中调用B,则中途将 程序控制权转到B,待B执行结束后再返 回到A。,函数嵌套调用示例,定义一个求 bin(n,k)的函
7、数。,分析:定义函数 fact(m)=m!bin(n,k)=fact(n)/(fact(k)*fact(n-k)由主函数输入数据 a、b,求 bin(a,b),试一下,函数嵌套调用示例#includelong fact(int m)int i;long sum=1;for(i=1;i a b;f1=fact(a)/(fact(b)*fact(a-b);cout first:bin(a,b)=f1 endl;f2=bin(a,b);cout second:bin(a,b)=f2 endl;,函数嵌套调用示例#includelong fact(int m)int i;long sum=1;for(
8、i=1;i a b;f1=fact(a)/(fact(b)*fact(a-b);cout first:bin(a,b)=f1 endl;f2=bin(a,b);cout second:bin(a,b)=f2 endl;,函数嵌套调用示例#includelong fact(int m)int i;long sum=1;for(i=1;i a b;f1=fact(a)/(fact(b)*fact(a-b);cout first:bin(a,b)=f1 endl;f2=bin(a,b);cout second:bin(a,b)=f2 endl;,函数嵌套调用示例#includelong fact(i
9、nt m)int i;long sum=1;for(i=1;i a b;f1=fact(a)/(fact(b)*fact(a-b);cout first:bin(a,b)=f1 endl;f2=bin(a,b);cout second:bin(a,b)=f2 endl;,5.2 函数的说明与使用,六、函数的嵌套与递归,函数递归:即自调用函数,在函数体内部直接 或间接地自己调用自己。,例如:下面的程序求n!,long fact(int n)if(n=1)return 1;return fact(n-1)*n;,5.2 函数的说明与使用,六、函数的嵌套与递归,函数递归,递推阶段:将原有问题不断地分
10、解为新的子问题,逐渐从未知向已知的方向推测,最终到达已知的条件,即递归结束条件,这时递推阶段结束。,递归调用 的过程,回归阶段:从已知条件出发,按照“递推”的逆过程,逐一求值回归,最后到达递推的开始处,结束回归阶段,完成递归调用。,5.2 函数的说明与使用,六、函数的嵌套与递归,函数递归,#include int f(int n)if(n=1)return 1;else return f(n-1)+n;void main()cout“s=”f(4)endl;,递归终止条件,修改递归条件,#include int f(int n)if(n=1)return 1;else return f(n-1
11、)+n;void main()cout“s=”f(4)endl;,f(4),f(4),f(4),f(3),f(3),f(2),f(2),f(1),f(4)=f(3)+4,f(3)=f(2)+3,f(2)=f(1)+2,f(4)=6+4=10,f(3)=3+3=6,f(2)=1+2=3,1,10,5.2 函数的说明与使用,七、内联函数,为什么要引进内联函数?,#include int isnumber(char);void main()char c;while(c=cin.get()!=n)if(isnumber(c)cout=0,#include int isnumber(char);void
12、 main()char c;while(c=cin.get()!=n)if(ch=0,5.2 函数的说明与使用,七、内联函数,2.内联函数的定义,inline 类型说明符 被调用函数名(形参表),内联函数具有一般函数的特性,它与一般函数的不同之处仅在于函数调用的处理。内联函数在调用时,是将调用表达式用内联函数体来替换。内联函数在开始时仅声明一次。,5.2 函数的说明与使用,七、内联函数,2.内联函数的定义,#include inline int isnumber(char);void main()char c;while(c=cin.get()!=n)if(isnumber(c)cout=0,
13、内联函数必须在被调用之前声明或定义。因为内联函数的代码必须在被替换之前生成。所以,程序若开始时不声明为inline,后面有inline也被视为普通函数。,内联函数中不能含有复杂的结构控制语句,如switch和循环语句。如果内联函数有这些语句,则编译将该函数视为普通函数那样产生函数调用。,递归函数不能用作内联函数。,内联函数只适用于15行的小函数。对一个含有许多语句的大函数,函数调用和返回的开销相对来说微不足道,没必要用内联函数来实现。,八、函数重载,函数重载是指同一个函数名可以对应着多个函数的实现,即支持多个不同的函数采用同一名字。,5.2 函数的说明与使用,八、函数重载,C+的函数如果在返回
14、类型、参数类型、参数个数、参数顺序上有所不同,则认 为是不同的。但重载函数如果仅仅是返 回类型不同,则是不够的,例如下面的 声明是错误的:,说明,void func(int);int func(int);,5.2 函数的说明与使用,八、函数重载,举例说明参数类型不同的重载函数的实现,例1,#include int abs(int x)return x0?x:-x;float abs(float x)return x0?x:-x;void main()cout“-10的绝对值是:”abs(-10)endl;cout“-2.5的绝对值是:”abs(-2.5)endl;,5.2 函数的说明与使用,举
15、例说明参数个数不同的重载函数的实现,例2,#include int min(int a,int b)return ab?a:b;int min(int a,int b,int c)int t=min(a,b);return min(t,c);int min(int a,int b,int c,int d)int t1=min(a,b);int t2=min(c,d);return min(t1,t2);void main()coutmin(13,5,4,9)endl;coutmin(-2,8,0)endl;,八、函数重载,typedef定义的类型只能使之相同于一个 已存在的类型,而不能建立新的
16、类型,所以不能用typedef定义的类型名来区分 重载函数声明的参数。例如下面的代码 实际上是同一个函数:,说明,typedef INT int;void func(int x)/void func(INT x)/error,5.2 函数的说明与使用,八、函数重载,让重载函数执行不同的功能,是不好 的编程风格。同名函数应该具有相同 的功能。如果定义一个abs()函数而 返回的却是一个数的平方根,则程序 的可读性受到破坏。,说明,5.2 函数的说明与使用,八、函数重载,使用重载,应避免产生二义性。,说明,包含缺省参数时,可能造成二义性。例如:,int sum(int a,int b,int c=
17、0);int sum(int a,int b);,5.2 函数的说明与使用,5.3 头文件与多文件结构,一、头文件,一个项目文件往往包含多个头文件(.h)和源文件(.cpp)一般将声明部分或者说明部分(包括类的声明)形成.h文件,将函数的定义、类的实现及类的使用等形成.cpp。,/examplech317.h 关于函数原型声明的头文件double cuboid(double x,double y);double cylinder(double h,double r);double spheroid(double r);,5.3 头文件与多文件结构,二、多文件结构,一个C+程序称为一个工程(.d
18、sp)一个工程由一个或多个文件组成 一个文件可以包含多个函数定义,但一个函数的定义必须完整地存在于一个文件中 一个文件可以被多个应用程序共享,计算圆面积和矩形面积,计算圆面积和矩形面积,计算圆面积和矩形面积,用指定正文替换程序中出现的标识符 形式#define 标识符 文本,#undef 功能是删除 由#define定义的宏,使之不再起作用,一、宏定义,5.4 编译预处理,/calculate.h#define CALCULATE_H/用后续4行正文代替CALCULATE_H double circle(double radius)const double pi=3.14159;return
19、pi*radius*radius;,include指令在编译之前把指定文件包含到该命令所在位置,#include 或#include 文件名,形式为:,系统头文件,二、文件包含,5.4 编译预处理,自定义头文件,所有编译指令以#开头,每条指令单独占一行,形式1#if 常量表达式程序段#endif,形式2#if 常量表达式程序段1#else程序段2#endif,形式3#if 常量表达式1程序段1#elif 常量表达式2程序段2#elif 常量表达式n程序段n#else程序段n+1#endif,三、条件编译,5.4 编译预处理,形式4#ifdef 标识符程序段1#else程序段2#endif,形式5#ifndef 标识符程序段1#else程序段2#endif,三、条件编译,5.4 编译预处理,如果标识符被#define定义,且没有执行undef语句,则编译程序段1,否则编译程序段2,没有程序段2,else可以省略,如果标识符没有被#define定义,则编译程序段1,否则编译程序段2,没有程序段2,else可以省略,
链接地址:https://www.31ppt.com/p-6613944.html