b函数与运算符的重载.ppt

上传人:max****ui 文档编号:3392380 上传时间:2019-12-13 格式:PPT 页数:106 大小:1.38MB
返回 下载 相关 举报
b函数与运算符的重载.ppt_第1页
第1页 / 共106页
b函数与运算符的重载.ppt_第2页
第2页 / 共106页
b函数与运算符的重载.ppt_第3页
第3页 / 共106页
点击查看更多>>
资源描述
1,第5章函数与运算符的重载,5.1.5.2.5.3函数的嵌套与递归5.4函数与运算符的重载5.5函数与C+程序结构5.6程序实例,2,问题,1,为什么要用函数2,使用函数的程序和顺序程序有什么区别?,3,5.3.1函数的嵌套,函数的嵌套一个函数的函数体中包含一个或多个函数调用语句,即称为函数嵌套。嵌套的含义是,如果函数A要调用函数B,也就是说,函数A的定义要依赖于函数B的定义。因此函数B的定义或函数B的原型必须出现在函数A的定义语句之前。另一方面,函数A调用函数B,在调用A的过程中,即执行A的函数体过程中,调用B,也就是中途把程序控制转到B的函数体,在执行结束后再返回到A的函数体中。函数嵌套调用所占用的空间(如赋值参数的创建等等)用堆栈(stack)的方式管理。一般这种堆栈所分配的空间是有限的,因此函数互相嵌套的层数也是有限的,依编译系统不同,其允许的嵌套层数也可能不同。,4,函数调用的堆栈情况,堆栈,Main(),cuberoot(x),参数传递、返回值,保护现场、恢复现场,调用,返回,5,实例,#includevoidf1(int,int);voidf2(int);voidmain()inta,b;couta;coutb;f1(a,a+b);coutendla+bendl;,voidf1(intx,inty)intm=2;x*=m;y+;f2(x+y)/m);voidf2(intp)if(p=100)coutendln;/输入的正整数放入n中longp=prod(n);/求出n的阶乘放入p中coutp=1*.*n=pn;ints=sum(n);/求出从1累加到n的和放s中couts=1+.+n=si;/输入if(n1)inv(n-1);/递归elsecout“-Theresult-”endl;/递归出口couti“”;/输出,voidmain(void)coutInput10integers:endl;inv(10);coutendl;,20,2反序输出从键盘输入的10个整数,可以有下面的执行结果:Input10integers:12345678910-Theresult-10987654321,21,3反序输出一个整数,在许多情形下递归函数易写易读,像解著名的Hanoi塔问题的递归函数,其递归程序很短,也极易理解(见5.6节),但是,如果不用递归方法,程序将十分复杂,很难编写。要求反序输出一个正整数的各位数值,如输入231,应输出132。,22,3反序输出一个整数,#includeintconv(intn)if(n10)coutn;return;/递归出口coutt;coutendl;conv(t);,23,3反序输出一个整数,输出结果为:Inputapositivenumber:47811874如果不用递归函数设计,程序不如递归形式清晰:,intconv(intn)if(n0)cout“Pleaseinputapositivenumber!”;elsedocout“下层”。也即,可从主调函数A中通过赋值参数所对应的实参将值“传入”到被调函数B内(去使用),但不可将被调函数B内改变后的参数值“传出”到主调函数A中(去接着使用)。系统处理方式为:被调函数中对形参值的改变不影响主调函数处的任一变量的值(形参分配有自己的局部于被调函数的存储空间,调用入口处将实参表达式的值赋给该局部变量)。,41,通过函数返回值(“单向传递”方式),通过函数内使用的return语句,可将被调函数B内计算出的最终值“传出”到主调函数A的“调用点”处(去接着使用)。也即,传值方向只是:“下层”=“上层”。,42,全局变量的定义域可延续到整个程序执行结束,因此,只要在函数中没有把该全局变量名说明为其它变量,在所有的函数中都可以直接访问它,也就是说,函数间的数据传递还可以通过全局变量实现,这种传递可以是双向的可从主调函数A中通过全局变量将值“传入”到被调函数B内(在A中赋值,进入B内后使用该值),又可将被调函数B内改变后的全局变量值“传出”到主调函数A中(去接着使用)。也即,传值方向可为:“上层”=“下层”,“下层”=“上层”。,2通过全局变量(“双向传递”方式),43,3通过引用参数(“双向传递”方式,有关引用的其它使用方法详见第6章),传值方向可为:“上层”=“下层”,“下层”=“上层”。即是说,它不仅可向被调函数的形参“传入”值(调用时的实参值),而且还可通过该形参“传出”值。系统处理方式为:被调函数中对形参值的使用与改变,就是对主调函数中调用语句处所对应实参变量值的直接使用与改变(形参不具有自己的局部于被调函数的存储空间,它只是实参变量的一个“替身”)。,44,4通过数组参数或指针参数(“双向传递”方式,指针参数的具体使用方法见第6章),传值方向可为:“上层”=“下层”,“下层”=“上层”。数组作形参,且在被调函数内使用或改变数组元素的值。系统处理方式为:对形参数组元素的使用与改变,就是对实参数组元素的直接使用与改变。指针作形参,且在被调函数内使用或改变指针所指变量的值。系统处理方式为:被调函数中对形参指针所指变量值的使用与改变,就是对实参指针所指变量值的直接使用与改变。,45,数组可作为函数参数,从而把主调函数中的整个数组(实际上是数组的首地址)传给了被调函数。而后可在被调函数中使用或改变传来的那些数组元素的值。但注意,若在被调函数内改变数组元素值的话,返回主调函数后,相应实参数组元素的值也进行了相同的改变(“双向传值”功能)。,数组参数,46,例1.读如下程序,看执行后会显示出什么结果?,#includevoidProcessingFunc(intb,intnum);/函数原型/int型数组形参b,通常省去对元素个数的指定/(当然也可以进行指定!)voidmain()intA10=0,1,2,3,4,9,8,7,66,88;cout-beforecalling,ai=-n;for(inti=0;i10;i+)coutAi;coutendl;,47,ProcessingFunc(A,10);/函数调用cout-aftercalling,ai=-n;for(i=0;i10;i+)coutAi;coutendl;,48,voidProcessingFunc(intb,intnum)/数组形参b,省去了对元素个数的指定!cout-inProcessingFunc,bi=-n;for(inti=0;inum;i+)coutbi;coutAi;ints=sum(A,n);couts=sendl;,53,程序中出现的所有名字(标识符)都必须说明,每个名字(变量名、常量名、参数名、函数名、类名、对象名等)都在程序的一定范围内有意义,就是该名字的作用域。1.外部存储属性与静态存储属性2名字的生存期与作用域,5.5.4变量与函数的作用域,54,一个C+程序由一个主函数和若干用户定义函数(或类)组成,当程序的规模较大时,整个程序可能被划分为几个程序文件,关键字extern(外部存储属性)和static(静态存储属性)可以规定所说明的变量名或函数名的作用域在一个程序文件范围内还是扩展到程序文件之外。,外部存储属性与静态存储属性,55,C+的存储类别,存储类别主要是针对变量而言的。变量不仅具有数据类型(存储空间大小),而且还具有存储类别(所占存储空间的期限,即生命期)。变量的存储类别可分为以下四种:自动(auto)型、寄存器(register)型、外部(extern)型、静态(static)型。,56,使用显式存储类别时,变量说明的一般格式变为:,.,;其中的“”可以是auto、register、extern、static四个关键字之一。C+程序的数据主要存放在如下两个数据区之中,一个称为静态数据区(也称全局数据区-“一旦分配,一直拥有”),另一个称为动态数据区(也称堆栈数据区-“入时分配并拥有,出时归还两手空”)。,57,具有程序级作用域以及文件级作用域的那些变量被分配在静态数据区之中。另外,具有static存储类别的变量也均被分配在静态数据区之中。在程序执行时,就为这种变量分配空间并进行隐式初始化(将数值量初始化为0,将字符量初始化为空格),直到程序执行结束时才释放这些存储空间。具有其它局部作用域的那些变量被分配在动态数据区之中。在程序执行时,每遇这种变量的作用域开始时就为其分配一次存储空间(但并不进行隐式初始化),而后,在每遇这种变量的作用域结束时就立即释放它们所占据的存储空间。,58,变量的存储类别,(1)自动(auto)变量与寄存器(register)变量这两类变量都是局部变量。均被分配在动态数据区之中。它们的“生命期”仅在其作用域之内。即是说,这两类变量的作用域与“生命期”具有一致性。由于C+编译器默认所有在函数或块内说明的局部变量均为自动(auto)变量,所以实用程序中根本不需要使用关键字auto。说明寄存器(register)变量时,必须使用存储类别register。如果没有足够多的通用寄存器,则编译器将它们按自动(auto)变量来处理。,59,(2)外部(extern)变量外部(extern)变量在所有的函数、类和名字空间之外说明的变量的作用域从被说明点开始,到所在的程序文件结束具有程序级作用域。它们被分配在静态数据区之中。即是说,它们是作用域最大且“生命期”最长的一种变量。在另一个程序文件中如果需要使用同一个变量的话,必须把这个变量说明为外部(extern)的,表示这个变量的说明不在本程序文件中,而在原文件之中。,60,(3)静态(static)变量又可分为局部静态变量和全局静态变量。局部静态变量是指在函数或块的内部说明的静态变量,它的作用域是局部的;对于局部变量:增加static说明,使其生存期扩展到整个程序。而全局静态变量指的是在所有函数的外部说明的具有单文件级全局性的静态变量。静态全局变量的生存期为整个程序,作用域为本程序文件,不可扩展。两种静态变量都被分配在静态数据区之中,即是说,它们的“生命期”都与整个程序的执行期相同。对于函数:一般(类外)函数的生存期和作用域为整个程序,静态属性的函数的作用域被限于所在的程序文件,这时,该函数不能在其它程序文件中使用。,61,函数的存储类别,函数也分为两种存储类别,一种是外部(extern)存储类别,另一种是静态(static)存储类别。(1)外部(extern)函数具有外部(extern)存储类别的函数称为外部(extern)函数。这种函数具有程序级作用域。当函数定义时没给出存储类别时,系统默认它为外部(extern)存储类别,所以实用程序中几乎从不使用extern来说明外部函数。,62,例如,如下的两个函数说明是完全等价的。intfunc()externintfunc()(2)静态(static)函数具有静态(static)存储类别的函数称为静态(static)函数(有时也称为内部函数)。这种函数只具有文件级作用域,即是说,这样的函数只能在本文件的内部被调用,在其它文件中均不可见。,63,存储类别相关实例,1.存储类别实例1-外部(extern)变量本实例程序由两个文件构成,下面分别叙述它们。(1)程序文件1本文件中对外部变量x及ch进行定义,并通过调用处于另一文件中的函数来“传递”与使用这些外部变量的具体值。,64,/file_1.cpp(源程序文件1,含有2个函数),#includeintx=11;charch=A;voidfunc1();/函数原型voidfunc2();/函数原型,具体定义在另一个文件中voidmain()func1();func2();coutInfile1_main:x,ch=x,chendl;voidfunc1()coutInfile1_func1:x,ch=x,chendl;,65,(2)程序文件2本文件通过extern关键字来对外部变量x及ch进行说明(不再分配存储空间,与另一文件定义处的那一同名变量共享同一存储空间),并通过使用与修改这些外部变量的值来达到文件间相互通讯的目的。,66,/file_2.cpp(源程序文件2,含有1个函数),#includeexternintx;externcharch;voidfunc2()coutInfile2_func2:x,ch=x,chendl;x=22;ch=B;程序执行后的显示结果如下:Infile1_func1:x,ch=11,AInfile2_func2:x,ch=11,AInfile1_main:x,ch=22,B,67,存储类别实例2-局部静态(static)变量,局部静态(static)变量与局部自动(auto)变量的使用区别是:它们的作用域都是局部的,作用域外都是不可见的;但局部静态(static)变量在其作用域外仍是存在的,而局部自动(auto)变量在其作用域外则不复存在。,68,#includevoidf1();voidmain()inti;for(i=1;i=3;i+)f1();voidf1()inta=1;/局部自动变量astaticints=1;/局部静态变量scoutInf1-pos1:a(auto)=as(static)=sendl;a+=2;s+=2;coutInf1-pos2:a(auto)=as(static)=snn;,69,程序执行后的显示结果如下:Inf1-pos1:a(auto)=1s(static)=1Inf1-pos2:a(auto)=3s(static)=3Inf1-pos1:a(auto)=1s(static)=3Inf1-pos2:a(auto)=3s(static)=5Inf1-pos1:a(auto)=1s(static)=5Inf1-pos2:a(auto)=3s(static)=7,70,名字的生存期和作用域,名字(变量名、函数名等等)的生存期与其对应的语法实体被分配的存储空间相关全局的、静态的、外部的语法实体被分配到全局数据区,生存期为整个程序局部的(在函数内,程序块内说明的)语法实体被分配到局部数据区(栈区等),这种分配是临时的,一旦该函数体或程序块这些结束,所分配的空间被撤销,局部名字的生存期从被说明开始,到程序块结束。从这里也可看到,生存期与一个程序被划分为一个或多个程序文件是没有关系的。名字的作用域与程序文件有关,作用域的概念是从这个名字能够被引用的,角度考虑的,一个名字在某处可以被引用,也称它在这里是可见的,它可被引用的范围,就是该名字的作用域。简单说作用域是指标识符(如变量名、参数名、函数名等)在程序正文中的有效范围。,71,(1)程序级作用域(也称多文件级作用域)属于程序级作用域的有通过extern存储类别进行说明的外部变量以及外部函数等。(2)文件级作用域(也称单文件级作用域)其有效范围为定义该标识符的那一个文件内。属于此种作用域的有静态函数以及在各函数之外的某一位置进行说明的那些变量等。(3)类级作用域有效范围为所定义的那一个类的类体内。类中的私有成员的作用域仅在其类体内,公有成员以及保护成员的作用域有所不同。关于类级作用域将在后面的章节再进一步讨论。,72,(4)函数级作用域(也称单函数级作用域)有效范围为所处的那一个函数的函数体内。属于此种作用域的有函数的形参、在函数体内说明的变量、以及语句标号等。(5)块级作用域块是程序正文中被一对花括号括起来的那一块区域(如,函数内的某一个复合语句)。C+允许在块中说明局部于该块的变量。,73,(6)函数原型级作用域,仅指出在函数原型声明时形式参数的作用范围。例如,假设有如下的函数原型声明:doublemyfunc(intipara);此时的形式参数ipara的有效范围(作用域)仅局限于说明该参数的那一对圆括号之间,在程序的其他任何地方都无法引用该标识符。,74,关于重名标识符的作用域,重名标识符指的是在程序中被重复定义的同名标识符。在相同的作用域内,标识符不能被重复定义。但在不同的作用域内,允许对标识符进行重复定义。重名标识符的作用域遵循如下的规则:(1)没有包含关系的两个不同作用域在其中说明的标识符尽管名字相同,但二者毫不相干。,75,(2)具有包含关系的两个不同作用域将它们看成是互不相同的名字;进入子范围后,将屏蔽其父范围的名字。即是说,进入子范围后,原父范围处定义的那一同名标识符将是不可见的,但它仍然存在;当退出了子范围后,原父范围处定义的那一同名标识符将又成为可见的了。,76,与作用域有关的程序实例,1.作用域实例1本实例出现了三个不同的作用域:函数级作用域,被函数级作用域所包含的外层块级作用域,被外层块级作用域所包含的内嵌块级作用域。,77,#includevoidmain()inti=10;/整型变量i,具有函数级作用域charch=1;coutinmain-i,ch=i,chendl;inti=20;/另一整型变量i,外层块级作用域charch=2;coutinlocal1-i,ch=i,ch0)doublei=30.3;/双精度变量i,内嵌块级作用域intch=33;coutinlocal2-i,ch=i,chendl;coutinlocal1-i,ch=i,chendl;coutinmain-i,ch=i,chendl;,79,程序执行后的显示结果如下:inmain-i,ch=10,1inlocal1-i,ch=20,2inlocal2-i,ch=30.3,33inlocal1-i,ch=20,2inmain-i,ch=10,1,80,2.作用域实例2本实例主要用于说明文件级作用域(全局变量),函数级作用域(局部变量),以及函数原型级作用域的相互关系及其使用。其中还出现了两个具有“平行”关系的函数作用域。,81,#includeintx=11;/x具有文件级作用域charch=1;voidfunc1(intipara1);/ipara1仅具有函数原型级作用域voidfunc2()inti=22222;/函数级i,与func1中i重名但不相干doublech=202.2;/函数级ch,与文件级ch同名coutinfunc2-x,ch=x,chendl;coutinfunc2-i=iendl;,82,voidmain()coutinmain-x,ch=x,chendl;func1(x);func2();voidfunc1(intii)inti=21111;/函数级i,与func2中i重名但不相干intx=201;coutinfunc1-ii=iiendl;coutinfunc1-x,ch=x,chendl;coutinfunc1-i=ielements;/输入整数elementsdoubleanswer=elements;intele=elements;,87,/求排列数A:共进行sel-1次乘法/A(ele,sel)=ele*(ele-1)*.*(ele-sel+1)for(i=1;iselections;i+)/循环sel-1次answer*=-ele;/最终的answer值即为所要求的A(ele,sel)coutA(elements,selections)=;coutanswerendl;/输出排列数A(ele,sel)之结果,88,/组合数C的求法:/C(ele,sel)=A(ele,sel)/sel!answer/=factorial(selections);/对递归函数调用,求阶乘coutC(elements,selections)=;coutanswerBC=BA=CB=AB=CA=C,104,具体程序如下:,#includevoidhanoi(int,char,char,char);/hanoi函数原型voidmain()intm;/欲移动的圆盘个数mcoutm;/输入圆盘个数mcoutendlThestepofmovingmdisks:;hanoi(m,A,B,C);/调用自定义函数hanoi,移m片,从A,借助B,到Ccoutendl;,105,voidmove(charfrom,charto)/移1片,从from,到to(“本原任务”)coutto;/显示移步信息,106,voidhanoi(intn,chara,charb,charc)/自递归函数hanoi,移n片,从a,借助b,到cif(n=1)move(a,c);/“本原任务”,递归出口elsehanoi(n-1,a,c,b);/移n-1片,从a,借助c,到b(递归调用)move(a,c);/移1片,从a,到c(“本原任务”)hanoi(n-1,b,a,c);/移n-1片,从b,借助a,到c(递归调用),
展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 图纸专区 > 课件教案


copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!