面向对象第四章_第1页
面向对象第四章_第2页
面向对象第四章_第3页
面向对象第四章_第4页
面向对象第四章_第5页
已阅读5页,还剩85页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

面向对象课件第四章第1页,课件共90页,创作于2023年2月第四章函数

§4.1

函数概述

§4.2

函数的定义和声明

§4.3

函数的调用

§4.4

参数传递

§4.5

标识符的作用域

§4.6

变量的生存期

§4.7

递归函数

§4.8

C++的库函数第2页,课件共90页,创作于2023年2月§4.1

函数概述

c++函数特点:独立完成某个功能的语句块封装了程序代码和数据,实现了更高 级的抽象减少代码重复,提高程序的可重用性第3页,课件共90页,创作于2023年2月§4.1

函数概述

函数的几个例子

例1: intbigger(inta,intb) { return(a>b)?a:b; } //找出最大数

获取参数并返回值第4页,课件共90页,创作于2023年2月§4.1

函数概述

例2: voiddelay(longa) { for(inti=1;i<=a;i++); } //延迟一个小的时间片

获取参数但不返回值第5页,课件共90页,创作于2023年2月§4.1

函数概述

例3: intgeti() { intx; cout<<“pleaseinputainteger:\n”; cin>>x; returnx; } //从键盘上获取一个整数

不获取参数但返回值第6页,课件共90页,创作于2023年2月§4.1

函数概述

例4: voidmessage() { cout<<“Thisisamessage.\n”; } //在屏幕上显示一条消息

不获取参数也不返回值第7页,课件共90页,创作于2023年2月§4.2函数的定义和声明

函数结构函数头+函数体

返回值函数名(参数表) { 函数体 }第8页,课件共90页,创作于2023年2月§4.2函数的定义和声明

函数结构答疑函数:询问老师参数:询问的题目返回:答案动作:解答题目订餐函数:订餐参数:订的菜单返回:是或否动作:做菜并送到家第9页,课件共90页,创作于2023年2月§4.2函数的定义和声明

函数的定义

一般形式:

类型函数名(形参表) { 语句组 }

注:1.默认的函数类型是int 2.不允许函数定义嵌套第10页,课件共90页,创作于2023年2月§4.2函数的定义和声明不允许函数定义嵌套如:

voidmain() { intfunc() { … } …… }函数独立完成某个功能,函数与函数之间通过参数和返回值联系参数---函数的输入返回值---函数的输出第11页,课件共90页,创作于2023年2月§4.2函数的定义和声明

函数的声明(即函数原型)

返回类型函数名(参数表);函数原型的作用: 声明了函数的参数情况及返回值第12页,课件共90页,创作于2023年2月§4.2函数的定义和声明说明: 1、函数原型是一条程序语句,须以分号结尾 2、函数原型的参数表中可只包含参数的类型如:

intarea(int,int);intarea(intlength,intwidth);左边也是合法的,只关心参数的个数和类型第13页,课件共90页,创作于2023年2月§4.2函数的定义和声明函数的定义和函数声明的关系 #include<iostream.h> #include<math.h> voidmain() { doublex; cout<<sin(x); }

函数原型doublesin(double);第14页,课件共90页,创作于2023年2月§4.2函数的定义和声明函数的定义与声明的关系

voidmain() { func(); } voidfunc() { …… }

voidfunc();voidmain() {func();}voidfunc(){ ……}第15页,课件共90页,创作于2023年2月§4.2函数的定义和声明

函数声明的原则:

如果一个函数定义在先,调用在后,调用前可不必声明 如果一个函数定义在后,调用在先,调用前必须声明第16页,课件共90页,创作于2023年2月§4.2函数的定义和声明

总结

1、函数在使用前必须先声明或先定义 2、函数的定义只有一次,但函数的声明可以 出现多次 3、函数的定义和声明必须在参数、返回值方 面保持一致第17页,课件共90页,创作于2023年2月§4.2函数的定义和声明例:原型 intarea(int,int); 调用c=area(10,5,8); 例:

voidfun(int,float); intmain() { inta; floatb; fun(a,b); } voidfun(int,int) { …… }

//参数个数不同参数类型不一致第18页,课件共90页,创作于2023年2月§4.2函数的定义和声明引用本文件外的函数时,需用#include将包含该函数的文件嵌入到当前位置#include有两种形式: 形式一:#include<文件名> 形式二:#include“文件名” 形式一用于C++提供的库函数,存放在C++系统目录中的include子目录中 形式二用于程序员开发的模块,存放在工作目录中第19页,课件共90页,创作于2023年2月§4.3函数的调用

1、函数的调用和返回 2、函数的调用过程 3、函数调用的实现—栈第20页,课件共90页,创作于2023年2月§4.3函数的调用

函数通过调用发挥作用在面向对象思想中,函数调用成为对象之间 发送消息的工具intA(){B();}intclassA::A(){classB::B();}第21页,课件共90页,创作于2023年2月§4.3函数的调用⑴函数调用语句

函数名(参数表);参数表,由0个,1个或多个实际参数组成实参的个数由形参决定,调用函数时实参给形参初始化实参对形参初始化是按其位置对应进行第22页,课件共90页,创作于2023年2月§4.3函数的调用⑵函数的返回

函数返回的条件: ①执行到函数的最后一条语句 ②遇到return语句(语句格式如下) return<表达式>; 或 return;第23页,课件共90页,创作于2023年2月§4.3函数的调用

return<表达式>;语句的实现过程

1、先计算出表达式的值;

2、当表达式类型与函数类型不同时,将表达 式的类型自动、强制性地转换为函数的类 型,可能出现不保值的情况

3、将表达式的值返回给调用函数

4、将程序执行的控制权由被调函数转向调用 函数,执行调用函数后面的语句第24页,课件共90页,创作于2023年2月§4.3函数的调用

return;语句

无返回值,只返回程序执行的控制权对于无返回值的函数须用void来说明类型在函数中return;语句可有可无若没有return;语句,执行到函数体的最后 一条语句时返回调用函数第25页,课件共90页,创作于2023年2月§4.3函数的调用

main函数main函数是由系统调用的第一个函数main函数直接或间接调用程序中所有其他函数main函数的参数通过命令行提供: 如:copyarg1arg2main函数返回值给调用它的系统 (0为正常返回,1为异常返回)main函数默认的类型是int第26页,课件共90页,创作于2023年2月§4.3函数的调用函数的调用过程main(){…………a();…………}a(){…………b();…………}b(){…………………………}第27页,课件共90页,创作于2023年2月§4.3函数的调用3.函数调用的实现--栈

栈中存放的内容: -调用函数的返回地址 -传递参数 -被调用函数的局部变量参数2

返回地址

参数1局部变量第28页,课件共90页,创作于2023年2月§4.3函数的调用

函数调用过程:①首先建立被调用函数的栈空间;②保护调用函数的运行状态和返回地址③传递函数实参给形参;④执行被调用函数的函数体内语句;⑤将控制权转交给调用函数第29页,课件共90页,创作于2023年2月§4.3函数的调用函数调用时栈的变化过程main()a()b()C()main()main()main()a()main()a()

b()main()a()

b()main()a()第30页,课件共90页,创作于2023年2月§4.3函数的调用 函数调用的实现——栈 说明:

函数的局部变量是临时存放的栈空间是有限的第31页,课件共90页,创作于2023年2月§4.4参数传递

参数传递方式传值调用设置参数的默认值第32页,课件共90页,创作于2023年2月§4.4参数传递参数传递方式:

⑴传值调用 单向:调用函数 ⑵传址调用(c语言中没有传址调用)

双向:调用函数被调用函数实参形参被调用函数实参形参第33页,课件共90页,创作于2023年2月§4.4参数传递C++变量的值有两种变量本身值(传值调用)变量地址值(传址调用)用指针实参:常量、变量值、表达式值形参:变量

第34页,课件共90页,创作于2023年2月§4.4参数传递传值调用的实现 函数调用时,系统先计算实参的值,再将实参的值按位置对应赋给形参。传值调用的实现机制 系统将实参拷贝一个副本(存放在被调用函数的栈中)给形参。传值调用的特点

形参值的改变不影响实参。第35页,课件共90页,创作于2023年2月例:#include<iostream.h> voidswap(int,int); voidmain() { inta=5,b=9; swap(a,b); cout<<“a=“<<a<<“,”<<“b=“<<b<<endl; } voidswap(intx,inty) { inttemp; temp=x; x=y; y=temp; cout<<“x=“<<x<<“,”<<“y=“<<y<<endl; }第36页,课件共90页,创作于2023年2月

程序运行结果: x=9, y=5 a=5,b=9

由执行结果可知:实参的值没有改变第37页,课件共90页,创作于2023年2月§4.4参数传递设置参数的默认值 当需要使用相同的实参反复调用某函数时,c++允许给参数设置默认值例: intfun(inta,intb=5,intc=8);fun函数的三个参数中,有两个设置了默认值第38页,课件共90页,创作于2023年2月§4.4参数传递例:voiddelay(intloops) { if(loops==0) return; for(inti=0;i<loops;i++); }函数声明:voiddelay(intloops=1000);函数调用:delay(2500); delay(); //loops使用默认值1000第39页,课件共90页,创作于2023年2月§4.4参数传递在设置和使用默认参数时应注意:⑴默认参数在函数声明中提供,当只有函数定义时,默认参数才可出现在函数定义中⑵一个函数的多个参数中,既有默认值也有非 默认值时应将默认值放在参数表的最右端。 如:

intfun(inti=8,charc,intj=45);//error!第40页,课件共90页,创作于2023年2月§4.4参数传递

⑶函数调用时,给定的实参值将取代参数的默认值,没有给定实参值将使用默认值

⑷默认参数即可以是数值,也可以是表达式第41页,课件共90页,创作于2023年2月§4.4参数传递例:分析程序的执行结果

#include<iostream.h> voidfun(inta=1,intb=2,intc=3) { cout<<“a=“<<a<<“,b=”<<b<<“,c=”<<c<<endl; } voidmain() { fun(); fun(9); fun(4,5); fun(7,8,9); }执行结果:a=1,b=2,c=3a=9,b=2,c=3a=4,b=5,c=3a=7,b=8,c=9第42页,课件共90页,创作于2023年2月§4.4参数传递例: #include<iostream.h> intq=5,p=7; intsum_int(inta,intb=q+p,intc=q*p); voidmain() { intx=5,y=10; ints1=sum_int(x); ints2=sum_int(x,y); cout<<“s1=”<<s1<<‘\n’<<“s2=“<<s2<<endl; } intsum_int(inti,intj,intk) { returni+j+k; }第43页,课件共90页,创作于2023年2月§4.5

标识符的作用域

作用域是指标识符的作用范围 在C++程序中出现的各种标识符,都有着不同的作用域标识符的作用域规则: 标识符只能在说明它或定义它的范围内是可见的(可进行存取或访问操作)第44页,课件共90页,创作于2023年2月§4.5标识符的作用域作用域的种类种类

作用域

程序级 组成该程序的所有文件文件级 从定义的地方起到文件结束函数级 函数体内。包括形参、函数内定义 的变量块级 从定义的地方起到相应的块尾 包括if、swicth、循环中定义的 变量作用域最大的是程序级,最小的是块级第45页,课件共90页,创作于2023年2月§4.5标识符的作用域例:

intglobal,i; voidfun1(intpara1,intpara2) { intlocal1,local2,j; if(para1==para2) { intk; …… } } intfun2() { …… }K块域local1,local2,j函数域global,i文件域第46页,课件共90页,创作于2023年2月§4.5标识符的作用域关于重新定义标识符的作用域规定在同一作用域内,不能有同名变量存在在不同的作用域内,允许定义同名变量第47页,课件共90页,创作于2023年2月§4.5标识符的作用域例: voidfun() { inta; floata; { floata; …… } …… }//非法//合法注:①块内的floata在块内可见,且存在②inta在块内不可见,但存在第48页,课件共90页,创作于2023年2月例:分析下列程序的输出结果#include<iostream.h>voidmain(){ inta=5,b=7,c=10; cout<<a<<“,”<<b<<“,”<<c<<endl; { intb=8; floatc=8.8; cout<<a<<“,”<<b<<“,”<<c<<endl; a=b; { intc; c=b; cout<<a<<“,”<<b<<“,”<<c<<endl; } cout<<a<<“,”<<b<<“,”<<c<<endl; } cout<<a<<“,”<<b<<“,”<<c<<endl;}运行结果:5,7,105,8,8.88,8,88,8,8.88,7,10第49页,课件共90页,创作于2023年2月例:分析下列程序的输出结果#include<iostream.h>voidmain(){ inti=5; for(;i>0;i--) { inti=25; cout<<i<<‘\t’; } cout<<‘\n’<<i<<‘\n’;}程序执行结果:2525252525 0

第50页,课件共90页,创作于2023年2月§4.5标识符的作用域局部变量与全局变量 在函数内或块内定义的变量为局部变量 在文件内或程序内定义的变量为全局变量局部变量的特点:提高函数的独立性和安全性全局变量的特点:可作为函数之间通信的一种方 式,但这种方式是不安全的, 不建议使用。第51页,课件共90页,创作于2023年2月§4.5标识符的作用域函数之间的通信方式有两种: ⑴参数传递和返回值 ⑵使用全局变量 在软件开发中,应尽量用参数传递取代全局变量,少用或不用全局变量第52页,课件共90页,创作于2023年2月例:演示局部变量与全局变量(书上96页程序4.4.1)#include<iostream.h>voidfunc1();voidfunc2();voidmain(){ cout<<“Novariablesdefinedinmain\n”; func1();}intage;voidfunc1(){ age=45; cout<<“Ageinfunc1()is”<<age<<‘\n’; func2();}voidfunc2(){ cout<<“Ageinfunc2()is”<<age<<‘\n’;}//问题:intage;移到不同位置时,其结果如何?第53页,课件共90页,创作于2023年2月§4.6

变量的生存期变量的存储类型C++程序的存储组织auto和register变量extern变量static变量第54页,课件共90页,创作于2023年2月§4.6

变量的生存期变量的存储类型 C++变量除有数据类型外还有存储类型

数据类型:决定变量的存储方式,取值范围, 可进行的操作

存储类型:决定变量的生存期,分配内存的 方式,初始化情况第55页,课件共90页,创作于2023年2月§4.6

变量的生存期变量具有下列四种存储类型之一: auto 自动型 register 寄存器型 static 静态型 extern 外部型修饰局部变量修饰局部、全局变量第56页,课件共90页,创作于2023年2月§4.6

变量的生存期变量的存储类型在定义变量时声明格式:

存储类型数据类型变量名; 例: autointi; staticcharc;

默认存储类型:

局部变量auto

全局变量extern第57页,课件共90页,创作于2023年2月§4.6

变量的生存期

C++程序的存储组织 内存分布:C++将内存分为四个部分程序代码程序数据堆栈静态区动态区全局变量静态变量动态申请的变量局部变量静态局部变量静态全局变量第58页,课件共90页,创作于2023年2月§4.6

变量的生存期静态区: ⑴该区内的变量具有全局寿命 ⑵初始化为0,且只初始化一次动态区: ⑴程序运行过程中根据需要动态分配与 释放内存空间 ⑵必须初始化,否则初始化值随机第59页,课件共90页,创作于2023年2月§4.6

变量的生存期例: inti; //局部变量 cout<<i; //未初始化就使用(垃圾值)

输出结果: -26956

一个程序两次调用同一个函数,分配给该函数中局部变量的内存地址可能是不同的第60页,课件共90页,创作于2023年2月§4.6

变量的生存期例:

{ …… intsum; //sum没有确定值 for(inti=1;i<=10;i++) sum+=i; cout<<sum<<endl; }

求和的值是无意义的应将intsum;改为intsum=0;第61页,课件共90页,创作于2023年2月§4.6

变量的生存期auto和register变量 特点:

⑴只修饰局部变量 ⑵局部寿命(生命期与作用域一致) ⑶必须初始化或赋值后才能使用 (没有默认值)第62页,课件共90页,创作于2023年2月§4.6

变量的生存期auto与register的区别

⑴register

的存取速度比auto快

⑵缺省是auto

(因此,局部变量一般不指定存储类型)第63页,课件共90页,创作于2023年2月§4.6

变量的生存期extern变量 特点:

⑴全局寿命(作用域最大,是整个程序)

⑵extern变量的定义和说明是两回事, 只能定义一次,可以说明多次 ⑶定义时,可省略extern,应定义在函数 体之外,可出现在程序头、中、尾

第64页,课件共90页,创作于2023年2月§4.6

变量的生存期

⑷说明时,须加extern,下列情况必须说明:

①同一文件中的外部变量,如果定义在后, 引用在先,引用前必须说明 ②在程序的一个文件中定义的外部变量, 要在程序中的另一个文件中引用,则引 用前必须说明 ⑸外部变量定义后,具有默认值: int型为0,char型为空,浮点型为0.0第65页,课件共90页,创作于2023年2月例: #include<iostream.h> voidmain() { externinta; intfun(int); inty=fun(a); cout<<y<<endl; } inta=5; intfun(intx) { intb=6; return(a+b)*x; }//说明外部变量a,因为a的定义在后//定义外部变量a,作用域是整个程序//b是auto型,作用域是fun()函数内//y是auto型,作用域是main()函数内//程序执行结果:55第66页,课件共90页,创作于2023年2月§4.6

变量的生存期static变量 特点:

⑴说明或定义时,须加static ⑵分为静态局部变量和静态全局变量 ⑶作用域与生命期不一致 ⑷定义或说明后具有默认值(同extern)

第67页,课件共90页,创作于2023年2月§4.6

变量的生存期静态变量可分为: 静态局部变量和静态全局变量二者的区别: 静态局部变量:定义在函数体内或程序块内 静态全局变量:定义在函数体外

第68页,课件共90页,创作于2023年2月§4.6

变量的生存期静态局部变量: 作用域是在定义它的函数体内或程序块内,而生命期是整个程序

(作用域内可见且存在,作用域外不可见但存在)第69页,课件共90页,创作于2023年2月§4.6

变量的生存期静态局部变量与auto变量的区别:

①auto变量的作用域与生命期一致

②auto变量每次调用,被重新初始化,

static变量每次调用都保留改变后的值例:静态变量用于调用计数

voidCountFun() { staticintcount=0; count++; cout<<“Youhavecalledme“<<count<<“times!”; }第70页,课件共90页,创作于2023年2月§4.6

变量的生存期静态全局变量 作用域是在定义或说明它的文件中,从定义或说明处开始到文件尾

生命期是整个程序第71页,课件共90页,创作于2023年2月例:分析程序执行结果

#include<iostream.h> voidmain() { inta=3; staticintb; //静态局部变量 b+=fun(a); cout<<“a=“<<a<<“,b=“<<b<<endl; b+=fun(a); cout<<“a=“<<a<<“,b=“<<b<<endl; } staticinta=10; //静态全局变量 intfun(intx) { staticintb=5; //静态局部变量 b+=a; cout<<“a=“<<a<<“,b=“<<b<<endl; returnb; }第72页,课件共90页,创作于2023年2月§4.6

变量的生存期程序执行结果 a=10,b=15 a=3,b=15 a=10,b=25 a=3,b=40第73页,课件共90页,创作于2023年2月§4.7

递归函数直接递归与间接递归递归调用的过程递归设计的要点举例:汉诺塔问题递归评价第74页,课件共90页,创作于2023年2月§4.7

递归函数递归函数有两种: 直接递归——自己调用自己 间接递归——A调用B,B调用A第75页,课件共90页,创作于2023年2月§4.7

递归函数直接递归与间接递归

直接递归

间接递归

A(intn) A(intn) { { …… …… A(n-1); B(n-1); …… …… } } B(intn) { …… A(n-1); ……

}第76页,课件共90页,创作于2023年2月§4.7

递归函数递归设计的要点递归结束条件

栈空间是有限的复杂性降低

f(n)变为f(n-1)或者f(n-2)的问题,参数 应逐渐逼近递归结束条件递归操作

每次递归能完成一些操作(具有一些功能)第77页,课件共90页,创作于2023年2月§4.7

递归函数递归调用的过程(两个阶段)

递推:先将原问题不断分解成新的子问题, 逐渐从未知向已知方向推测,最后到 达已知条件,即递归结束条件

回归:从已知条件出发,按“递推”的逆过程, 逐一求值回归,最后到达递归开始处, 结束回归,完成递归调用第78页,课件共90页,创作于2023年2月§4.7

递归函数求n!的递归算法求值过程说明上述两个阶段

3!=3*2! 3!=3*2!=3*2=6

2!=2*1! 2!=2*1!=2*1=2 1!=1*0! 1!=1*0!=1*1=1

0!=1递推①递推②递推③回归①回归③回归②第79页,课件共90页,创作于2023年2月§4.7

递归函数求n!的函数定义

longfact(intn) { if(n==0) //递归结束条件 return1; returnn*fact(n-1); //递归调用语句 }

第80页,课件共90页,创作于2023年2月例:从键盘输入一个正整数,编程求出该数的阶乘

#include<iostream.h> long

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论