




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、1第第1章内容回顾章内容回顾vC 和 C+起源 C 的优缺点 过程化程序设计和面向对象程序设计 最简单的C+程序2第2章引用和函数的高级用法引用和函数的高级用法3本章目标本章目标v学完本章内容以后,你将能够对C+引用,重载函数,内联函数,默认参数的函数,递归函数有个深刻的理解掌握和应用。 引用的优点和使用方法 函数 内联函数 重载函数 默认参数函数 递归函数4本章结构本章结构引用和函数的高级用法引用和函数的高级用法引用引用引用概念引用概念操作引用操作引用引用条件引用条件引用传递函数参数引用传递函数参数函数多个返回值函数多个返回值const 限制限制高级函数特性高级函数特性内联函数内联函数递归函
2、数递归函数重载函数重载函数默认参数的函数默认参数的函数52-1-1 引用的概念引用的概念 1 1、创建引用的格式:、创建引用的格式:Type & Type & 变量名变量名 = = 引用的变量引用的变量 例:例:int a =10; int a =10; int& ret = a;int& ret = a;2 2、引用的使用:、引用的使用:与一般变量的使用格式相同与一般变量的使用格式相同 例:例:cout ret endl;cout ret endl;3 3、引用的特点、引用的特点引用引用: :引用的实质是某变量的别名;引用的实质是某变量的别名;对引用的操作实质
3、是对所引用变量的操作对引用的操作实质是对所引用变量的操作引用的地址与所引用变量的地址相同引用的地址与所引用变量的地址相同注意:&只有在声明引用时是引用操作符只有在声明引用时是引用操作符, ,其他时候都是地址操作符其他时候都是地址操作符62-1-2 引用的使用引用的使用 int a = 10;int &ret; /错误错误int &ret = a;cout a: a ret: retendl; cout &ret: &ret &a:&a endl; ret = 30; cout a: a ret:retendl; int& ret2
4、 = 10; /错误错误const int & ret2 = 10;输出结果输出结果相同相同输出结果输出结果相同相同1、声明引用时必须初始化2、C+没有提供访问引用本身地址的方法,引用取地址所取得的地址与取得变量的地址相同2、引用的类型与所引用变量的类型必须一致72-1-2 引用的使用引用的使用通过引用修改变量的值int intOne;int& rInt=intOne;intOne=5;cout &intOne: &intOne endl;cout &rInt: &rInt endl;int intTwo=8;rInt=intTwo;cout i
5、ntOne: intOne endl;cout intTwo: intTwo endl;cout rInt: rInt endl;cout &intOne: &intOne endl;cout &intTwo: &intTwo endl;cout &rInt: &rInt endl;运行结果运行结果:&intOne: 0 x0012ff28&rInt: 0 x0012ff28intOne:8intTwo:8rInt:8&intOne: 0 x0012ff28 &intTwo:0 x0012ff20&rInt
6、: 0 x0012ff281、引用一旦初始化,它就维系在一定的目标上,再也不分开2、引用与指针的区别:指针所指向的地址可变,引用与变量的关系不变;指针声明时可不初始化,引用声明时必须初始化;82-1-3 指针引用指针引用 int a = 10,b = 20;int *p = &b; int *& ret2 = p; int &* ret4 = &ret2; /错误cout“*&ret2:”ret2“&b:”&bendl; ret2 = &a;cout“p:”p“ ”“&a:”&a“ ”“ret2:”ret2endl
7、; 1、指针也是变量,所以可以有指针变量的引用:2、指针引用保存的是指针的内容(变量的地址)3、通过指针引用改变了原指针的指向的地址4、指针引用的特性与指针相类似,与一般引用不同注意:当一个引用所引用的是一个指针时(指针引用),此时引用的用法与指针一样9引用的常见错误引用的常见错误1、 void&a;有void指针没有void引用2、 int a10; int& ra10 = a; 3、int a; int& ra = a; int& *p = &ra; 有指针的引用和指针的指针,没有引用的指针和引用的引用4、 int& ri = NULL; 有
8、空指针无空引用5、 int& ra = int; 引用不能用类型来初始化102-1-4 引用作函数参数引用作函数参数 v 传递引用给函数与传递指针的效果一样(传址调用)v 用引用作为参数比使用指针要容易理解 用引用实现swap函数:void swap(int&x ,int& y) int temp; temp = x; x = y; y = temp; 调用:调用:int a = 10,b = 20; swap(a,b); 11函数调用传值调用(值传递)传值调用(值传递):方法内的改变不会影响到方法外:方法内的改变不会影响到方法外: : 函数在被调用以前,函数在被调用以
9、前,形参变量并不占内存单元,当函数被调用时,形参变量分配有存储单元,并将形参变量并不占内存单元,当函数被调用时,形参变量分配有存储单元,并将相应的实参变量存储单元的值复制到形参变量单元。所以,被调函数在执行过相应的实参变量存储单元的值复制到形参变量单元。所以,被调函数在执行过程中,如果形参变量的值发生了变化,并不影响实参变量的值。程中,如果形参变量的值发生了变化,并不影响实参变量的值。传址调用(引用传递):传址调用(引用传递):方法内的改变会影响到方法外方法内的改变会影响到方法外把实参在内存中的地址传给了形参,在被调函数中,如果改变了形参某元素的把实参在内存中的地址传给了形参,在被调函数中,如
10、果改变了形参某元素的值,在被调函数中,实参对应元素的值也会发生相应的改变。值,在被调函数中,实参对应元素的值也会发生相应的改变。传值调用与传址调用的区别:传值调用与传址调用的区别:使用传值调用时,函数接收的是函数值的一份拷使用传值调用时,函数接收的是函数值的一份拷贝;另一方面,使用传址调用时,函数接收的是变量的内存地址。因此,函数贝;另一方面,使用传址调用时,函数接收的是变量的内存地址。因此,函数能改变存放于指定内存单元(也就是变量值)的值,所作的改变在函数结束后能改变存放于指定内存单元(也就是变量值)的值,所作的改变在函数结束后继续保留下来。继续保留下来。C+C+中的传值与传址中的传值与传址
11、如果函数定义时:形参类型为基本类型、一般结构体是传值调用如果函数定义时:形参类型为基本类型、一般结构体是传值调用如果函数定义时:形参类型为数组、指针、引用是传址调用如果函数定义时:形参类型为数组、指针、引用是传址调用122-1-4 引用作函数参数引用作函数参数 传递引用给函数的内存布局把引用作形参,则将做实参的一般变量传给形参时,传入到形参的是实把引用作形参,则将做实参的一般变量传给形参时,传入到形参的是实参的别名,通过别名对变量进修改,就会将实参的值修改了参的别名,通过别名对变量进修改,就会将实参的值修改了132-1-4 引用作函数参数引用作函数参数 潜在问题 因为将引用作为函数参数时,函数
12、调用与一般函数调用一致,但是所产生的效果却不一样(一个传值,一个传址),所以当我们不想在函数中改变时,使用引用作为参数就可能改变参数 int a=5;int b=6;fun(a,b);调用形式和非调用形式和非引用参数的函引用参数的函数是一样的数是一样的解决办法解决办法:void fun(const int& x ,const int& y)142-1-5 引用作返回值引用作返回值 问题:函数返回值时,要生成一个值的副本,并且系统要执行将这个副本调入调用函数。有没有办法提高系统效率呢? 使用引用作为参数和返回值给函数的意义 而用引用返回值时,不生成值的副本,所以提高了效率 int
13、 temp; float& fn2(float r) / 返回引用返回引用 temp = r*r*3.14;return temp;152-1-5 利用引用返回值利用引用返回值 返回值和返回引用的内存对比返回数值返回数值返回引用返回引用162-1-5 引用作返回值引用作返回值 v 注意注意: 如果返回不在作用域范围内的变量或对象的引用那就有问题了。这与返如果返回不在作用域范围内的变量或对象的引用那就有问题了。这与返回一个局部作用域指针的性质一样严重回一个局部作用域指针的性质一样严重float& fn2(float r)float temp;temp=r*r*3.14;retur
14、n temp; /返回局部变量的引用返回局部变量的引用int main()float &d=fn2(5.0); /警告,返回的引用是个局部变量警告,返回的引用是个局部变量 cout d endl; return 0;172-1-5 引用作返回值引用作返回值 v 解决办法:返回全局变量的引用解决办法:返回全局变量的引用float s;float& fn2(float r) s = r*r*3.14; return s; int main() float r = 5.0; float &d=fn2(r); /正确正确cout d endl; return 0;182-1-5
15、 引用作返回值引用作返回值 v 解决办法:将形参设置为引用解决办法:将形参设置为引用float& fn2(float &r) r = r*r*3.14; return r; int main() float r = 5.0; float &d=fn2(r); /正确正确cout d endl; return 0;19利用引用返回值解决办法:解决办法:将返回值存入引用形参将返回值存入引用形参void add(int a,int b,int &result) result = a + b; int main()int a = 10,b = 20,ret;add(a,
16、b, ret);couttemp: ret endl;202-1-6 const 限制限制 v传递指针和引用更大的目的是效率v传递的地址特征使得所传的参数处于随时被修改的危险之中 保护实参不被修改的办法是传递const 指针和引用 引用总是const的 如果对引用应用关键词const,其作用就是使目标成为const变量21const int& add(int& a,const int& b) /return b += a; / 错误错误return a += b; int main() int a = 10,b = 20; const int& result2
17、= add(a,b); cout result2 = result2 endl; / result2 = 80; /错误错误int result = add(a,b); / 正确正确cout result = result endl;result = 80; /正确正确const 限制限制22结构与引用结构与引用使用结构引用作为参数传递使用结构引用作为参数传递:#include using namespace std;struct studentchar name10;int sno;void getStudent(struct student & stu) coutplease in
18、put name ; coutplease input sno stu.sno;void show(struct student & stu) coutname is: sno is:stu.snosno = sno; int getsno() const / this-sno = 20; /常函数中不能改变类成员的值 return this-sno; ;int main() student s(10); int sno = s.getsno(); cout sno = sno endl;const 限制限制24阶段总结阶段总结引用可以提高程序的可读性在
19、大对象时,引用可以提高效率引用可以变相增加函数的返回值数组不可以引用 避免返回局部变量的引用可以返回结构的引用25阶段练习阶段练习J一个变量可以有多少个引用?J为什么不要返回局部变量的引用?J引用为什么总是const的?26返回值返回值函数函数输入数据流输入数据流输出数据流输出数据流函数能够从输入数据或参数函数能够从输入数据或参数获得信息获得信息参数参数函数处理完的信息用函数处理完的信息用返回值或输出数据流返回值或输出数据流输出输出2-2 函数函数27内联函数内联函数v 函数调用与堆栈1)编译器一般使用栈来存放函数的参数,局部变量等来实现函数调用。有时候函数有嵌套调用,这个时候栈中会有多个函数
20、的信息,每个函数占用一个连续的区域。一个函数占用的区域被称作帧。 28内联函数内联函数 从上面的图中我们可以看出每一次函数的调用都涉及到:1、系统在函数调用前为函数所分配的帧2、系统在函数调用完成时将帧回收 问题:如果一个函数的代码量很少,只有几行代码,但是系统也要为其执行相同的操作,有没有办法减少系统的这部分开销呢?(将这部分代码嵌入调用函数之中)fn1()fn1()fn1()fn1()fn1();语句;fn1();mfunc();fn1();funcy();main()main()重复地放到函数中的代码放在内联函数中的代码292-2-1 内联函数内联函数内联函数的特点:内联函数从源代码层看
21、,有函数的结构,而在编译后,却不具备函数的性质。编译时,类似宏替换,使用函数体替换调用处的函数名。注意:能否形成内联函数,需要看编译器对该函数定义的具体处理。内联函数的定义:inline tablefunction(int i) return i*i;使用内联函数的时候要注意:1.递归函数不能定义为内联函数2.内联函数只适合于不存在while和switch等复杂的结构且只有15条语句的小函数,否则编译系统将该函数视为普通函数。3.内联函数只能先定义后使用,因为内联函数的代码必须在被替换之前已经生成被替换的代码。 否则编译系统也会把它认为是普通函数。4.对内联函数不能进行异常的接口声明。30v
22、2-2-1 内联函数内联函数#includeusing namespace std;inline int isnumber(char ch)return (ch = 0 & ch = 9)?1:0;int main()char c; while(c=cin.get()!=n) if(isnumber(c) /调用一个小函数调用一个小函数 cout you entered a digit n; else cout you entered a non-digit n; 312-2-1内联函数与宏定义 v 宏定义的缺陷宏定义的缺陷 宏只是告诉编译器简单的替代代码宏只是告诉编译器简单的替代代码
23、,不检查参数类型不检查参数类型, 往往造成语句的实际结果不能代表程序员的意图(例)往往造成语句的实际结果不能代表程序员的意图(例) 宏的作用可以用内联函数代替宏的作用可以用内联函数代替: #define JFT(x) (x)*(x)通过一个内联函数可以得到所有宏的替换功能和所有可预见的状态以及常规通过一个内联函数可以得到所有宏的替换功能和所有可预见的状态以及常规函数的类型检查:函数的类型检查: inline int JFT(int a, int b) return a*b;322-2-2 重载函数重载函数问题:在C中,每个函数必须有其唯一的名字。例:求不同数据类型的绝对值,必须定义多个不同名的
24、函数解决不同类型数据的求绝对值问题。 int abs(int); long labs(long); double fabs(double);这几个函数所做的事情是一样的,都是求绝对值,但却要定义不同的函数名,给函数的调用带来了不方便 函数重载:函数重载:在同一范围中,在函数定义时,有两个以上的函数,取相同的函数在同一范围中,在函数定义时,有两个以上的函数,取相同的函数名,但是形参的个数、类型、顺序不同。在函数调用时,编绎器根据实参和形参名,但是形参的个数、类型、顺序不同。在函数调用时,编绎器根据实参和形参的类型、个数、顺序不同而自动选择最佳匹配,自动确定调用哪一个函数,这就的类型、个数、顺序不
25、同而自动选择最佳匹配,自动确定调用哪一个函数,这就是函数的重载。是函数的重载。 332-2-2 重载函数重载函数v求绝对值的例子求绝对值的例子: int abs(int); long abs(long); double abs(double);v C+用一种函数命名技术可以准确判断出应该使用哪个abs()函数。 abs(-10);/调用int abs(int); abs(-1000000);/调用long abs(long); abs(-12.23);/调用double abs(double);34v匹配重载函数规则匹配重载函数规则 寻找一个严格的匹配,如果找到了,就用那个函数。 通过内部转换
26、寻求一个匹配,只要找到了,就用那个函数。2-2-2 重载函数重载函数void print(double);void print(int);print(1); /匹配匹配void print(int);print(1.0); /匹配匹配void print(double);print(a); /匹配匹配void print(int);print(31415f); /匹配匹配void print(double);35对于重载函数对于重载函数print()声明,其下面的函数调用将引起错误声明,其下面的函数调用将引起错误2-2-2 重载函数重载函数#includeusing namespace std
27、;void print(long a) cout a endl;void print(double a) cout a 2) return (flb(x -1)+flb(x-2);/直接递归直接递归 else return 1; 40递归调用例:用递归实现的计算阶乘的例:用递归实现的计算阶乘的C+C+函数:函数:int RecursiveFactorial(int n) int RecursiveFactorial(int n) if (n = 0)if (n = 0)return 1;return 1;else return n else return n * * RecursiveFact
28、orial(n - 1); RecursiveFactorial(n - 1); 41递归调用递归调用422-2-3 递归函数递归函数递归的条件递归的条件递归函数的结构递归函数的结构(1 1) 要有递归终止条件检查要有递归终止条件检查(2 2) 如果不满足递归终止的条件,则返回涉及递归调用的表达式如果不满足递归终止的条件,则返回涉及递归调用的表达式 (3) (3) 先测试,后递归调用先测试,后递归调用int RecursiveFactorial(int n) if (n = 0) /递归终止的条件递归终止的条件return 1;else return n * RecursiveFactoria
29、l(n - 1); /不满足条件返回递归调用不满足条件返回递归调用 432-2-3 递归函数递归函数v 消去递归消去递归 大多数递归函数都能用非递归函数来代替。大多数递归函数都能用非递归函数来代替。计算阶乘的计算阶乘的C+函数,它是用循环来实现的:函数,它是用循环来实现的:int Factorial(int n) int result = 1; int i; for (i = 1; i = n; i+) result *= i;return result; 442-2-3 递归函数递归函数v递归的评价 递归的目的是简化程序设计,使程序易读 递归增加了系统开销现代程序设计的目标主要是可读性好。对
30、于嵌入式来说,由于系统性能有限,用递归要慎重452-2-4 参数默认的函数参数默认的函数v C+中在定义函数时,可以给形参设置默认值: int add(int x = 5,int y = 6,int z = 3);v 在调用时,则可以省略部分参数 main( ) add( ); /所有这三个参数都采用默认值所有这三个参数都采用默认值 add( 1,5); /第三个参数采用默认值第三个参数采用默认值add(1,2,3); /不使用默认值不使用默认值462-2-4 参数默认的函数参数默认的函数v默认参数的顺序规定默认参数的顺序规定 如果一个函数中有多个默认参数,则形参分布中,默认参数应从右至左逐渐定义。当调用函数时,也只能从右向左匹配参数。例如: 对于第2个函数声明,其调用的方法规定为:void func(int a=1,int b,int c=3,int d=4); /errorvoid func(int a,int b=2,int c=3,int d=4); /okfunc(10,15,20,30);/0k:调用时给出所有实参:调用时给出所有实参func();/error:参数:参数a没有默认值没有默认值func(12,12); /ok:参数:参数c和和d默认默认func(2,15,20
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 仪表合同范例
- 公司临时合同范例
- 主体工程合同范例
- 信息咨询销售合同范例
- 人工色素采购合同范例
- 兄弟农村房屋买卖合同范例
- oa合同范例软件
- 2025年入团价值体系试题及答案
- 个体店铺转租合同范例
- 复杂问题中级会计试题及答案
- 高职健康评估教学模式创新的探索与实践
- 消防救援-消防火场供水
- 地铁防淹门系统的方案比选和设计
- 办理证件协议书
- PAC(流产后关爱)项目之流产与避孕培训课件
- 山西煤炭运销集团三元石窟煤业有限公司矿山矿产资源开发利用、地质环境保护与土地复垦方案
- 团队项目任务完成进度跟进表模板
- 山东省应急管理普法知识竞赛参考题库-中(多选题)
- 聂耳音乐课件人物介绍
- 2023年教师基本功市级考核初中物理试卷
- PPAP项目计划表模板
评论
0/150
提交评论