C++函数和函数模板详解.ppt

上传人(卖家):hwpkd79526 文档编号:6157859 上传时间:2023-06-04 格式:PPT 页数:96 大小:749.50KB
下载 相关 举报
C++函数和函数模板详解.ppt_第1页
第1页 / 共96页
C++函数和函数模板详解.ppt_第2页
第2页 / 共96页
C++函数和函数模板详解.ppt_第3页
第3页 / 共96页
C++函数和函数模板详解.ppt_第4页
第4页 / 共96页
C++函数和函数模板详解.ppt_第5页
第5页 / 共96页
点击查看更多>>
资源描述

1、第第3章章 函数和函数模板函数和函数模板C+语言的模块设计离不开函数,函数设计更离不语言的模块设计离不开函数,函数设计更离不开参数。在面向对象程序设计中,成员函数也是函开参数。在面向对象程序设计中,成员函数也是函数,只是它们的类型及其返回值更复杂些。由此可数,只是它们的类型及其返回值更复杂些。由此可见,熟练地掌握函数知识,是非常必要的。见,熟练地掌握函数知识,是非常必要的。掌握函数设计和调用的正确方法,是程序设计的基掌握函数设计和调用的正确方法,是程序设计的基本功。正确设计函数原型和参数类型,不仅能保证本功。正确设计函数原型和参数类型,不仅能保证函数的正确性,而且能提高程序设计的效率。函数的正

2、确性,而且能提高程序设计的效率。本章除介绍函数调用、递归调用、以及函数调用中本章除介绍函数调用、递归调用、以及函数调用中的参数替换和返回值等问题之外,还将结合软件编的参数替换和返回值等问题之外,还将结合软件编程技术的发展,讨论函数指针、内联函数、函数重程技术的发展,讨论函数指针、内联函数、函数重载、函数模板及算法知识等,但不涉及类的构造函载、函数模板及算法知识等,但不涉及类的构造函数和成员函数。数和成员函数。3.1 函数基本要素函数基本要素3.2 函数调用形式函数调用形式3.3 函数参数的传递方式函数参数的传递方式3.4 深入讨论函数返回值深入讨论函数返回值3.5 内联函数内联函数3.6 函数

3、重载和默认参数函数重载和默认参数3.7 函数模板函数模板主要内容主要内容3.1 函数基本要素函数基本要素1.函数值和函数值和return语句语句一般情况下,函数必须返回与函数声明相一致的值作为函一般情况下,函数必须返回与函数声明相一致的值作为函数的值。函数返回使用如下形式实现:数的值。函数返回使用如下形式实现:return(表达式)(表达式);称称return为返回语句。这里的表达式的值就是要返回的函为返回语句。这里的表达式的值就是要返回的函数值。表达式两边的圆括号可有可无。数值。表达式两边的圆括号可有可无。return语句在一个语句在一个函数里可以多次使用,但返回值的类型必须一致且与函数函数

4、里可以多次使用,但返回值的类型必须一致且与函数的类型说明一致。当函数不需要带值返回时,将函数直接的类型说明一致。当函数不需要带值返回时,将函数直接定义为定义为void类型,最为方便。这样就不必在函数体内使用类型,最为方便。这样就不必在函数体内使用return语句。语句。实际上,最后一个大括号实际上,最后一个大括号“”有有return语句的作用语句的作用(函数函数末尾隐含有一个末尾隐含有一个return语句语句)。若函数不带值返回,实际上并不是不返回什么值,而是返若函数不带值返回,实际上并不是不返回什么值,而是返回一个不定值。回一个不定值。因为不考虑使用,所以尽管返回的是不定值,也就没有多因为不

5、考虑使用,所以尽管返回的是不定值,也就没有多大关系了。也可以在函数体内使用不带表达式的大关系了。也可以在函数体内使用不带表达式的return语语句,即句,即 return;【例【例3.1】作为认识返回值的练习,写一个具有两个】作为认识返回值的练习,写一个具有两个string类型参数的函数类型参数的函数max,比较这两个参数,比较这两个参数(字符串字符串)的的大小,并把大者作为函数的返回值。大小,并把大者作为函数的返回值。下面的主函数调用下面的主函数调用max函数,执行该程序,函数,执行该程序,str的值就等的值就等于于str1、str2中大的一个。为了分析方便,使用注释为程中大的一个。为了分析

6、方便,使用注释为程序语句编号。序语句编号。#include /1#include /2using namespace std;/3string max(string,string);/4void Welcome();/5void main()/6 /7 Welcome();/8 string str1(abc),str2(abC),str;/9 str=max(str1,str2);/10 coutstr=str s2)return s1;/15 else return s2;/16 /17void Welcome()/18cout欢迎使用欢迎使用string类。类。s2)str=s1;els

7、e str=s2;return str;main函数内部和函数内部和max函数内都有变量函数内都有变量str,两个变量,两个变量str都是在各自的都是在各自的“”内声明的变量,这样的变量叫做局部内声明的变量,这样的变量叫做局部变量。虽然它们使用了相同的变量名,但互不影响。变量。虽然它们使用了相同的变量名,但互不影响。3.2 函数调用形式函数调用形式函数的调用方法是在表达式、语句或参数中直接写出函函数的调用方法是在表达式、语句或参数中直接写出函数名,并用实参代替形参。一旦出现被调用的函数,就数名,并用实参代替形参。一旦出现被调用的函数,就要转去执行这个函数,并将该函数执行结果返回来。根要转去执行

8、这个函数,并将该函数执行结果返回来。根据被调用函数在源程序中出现的位置,把函数调用分为据被调用函数在源程序中出现的位置,把函数调用分为语句调用、表达式调用和参数调用语句调用、表达式调用和参数调用3种形式。种形式。3.2.1 函数语句调用函数语句调用被调用函数作为一个独立的语句出现在源程序中,这种被调用函数作为一个独立的语句出现在源程序中,这种语句就叫函数语句。这种调用很简单,只要把被调用函语句就叫函数语句。这种调用很简单,只要把被调用函数的函数名直接写出来,并以实参替换原来的形参即可。数的函数名直接写出来,并以实参替换原来的形参即可。函数调用也可以嵌套,且与函数的编写顺序没有关系。函数调用也可

9、以嵌套,且与函数的编写顺序没有关系。【例【例3.1】中第】中第8行的语句行的语句“Welcome();”就是函数语句就是函数语句调用,这种被调用的函数没有返回值。调用,这种被调用的函数没有返回值。3.2.2 函数表达式调用函数表达式调用被调用函数出现在一个表达式中,这种表达式也可叫做函被调用函数出现在一个表达式中,这种表达式也可叫做函数表达式,它用在被调用函数有返回值的情况。【例数表达式,它用在被调用函数有返回值的情况。【例3.1】中的语句中的语句“str=max(str1,str2);”,就是函数表达式调用。,就是函数表达式调用。3.2.3 函数参数调用函数参数调用被调用函数作为函数的一个参

10、数(函数参数)出现。这种被调用函数作为函数的一个参数(函数参数)出现。这种调用虽然形式上不同于函数表达式调用,但调用条件和注调用虽然形式上不同于函数表达式调用,但调用条件和注意事项与函数表达式调用是相同的。意事项与函数表达式调用是相同的。【例【例3.2】函数参数调用的例子。】函数参数调用的例子。#include#include using namespace std;string max(string,string);void main()string str1(abc),str2(abC),str3(b),str;str=max(str1,max(str2,str3);coutstr=str

11、 s2)return s1;else return s2;程序先调用程序先调用max求求str2和和str3中的大者中的大者(b),再将这个返回,再将这个返回值作为值作为max函数的一个参数,求函数的一个参数,求“b”与另一个数与另一个数str1的大的大者,输出者,输出“str=b”。即。即max(str2,str3)作为函数作为函数max的参的参数。调用函数时,参数替换的实质是把实参数值赋给形参数。调用函数时,参数替换的实质是把实参数值赋给形参变量,这叫做传值。变量,这叫做传值。3.2.4 递归调用递归调用函数调用,一般是一个函数调用另外一个函数。此外,函函数调用,一般是一个函数调用另外一个

12、函数。此外,函数还可以自己调用自已,这种调用叫做函数的递归调用。数还可以自己调用自已,这种调用叫做函数的递归调用。递归调用有两种方式,一种是直接调用其本身,另一种是递归调用有两种方式,一种是直接调用其本身,另一种是通过其他函数间接地调用。在这里只给出直接递归调用的通过其他函数间接地调用。在这里只给出直接递归调用的例子。例子。【例【例3.3】求阶乘的递归调用程序。求阶乘的递归调用程序。#include using namespace std;int factorial(int);void main()int n;coutn;coutn!=factorial(n)endl;int factoria

13、l(int x)if(x=0)return 1;else return(x*factorial(x-1);运行输入:运行输入:Input n=5显示结果:显示结果:5!=120main函数调用函数调用factorial函数。其中函数。其中factorial有返回值,函有返回值,函数递归调用时,每调用一次其自动型变量就占据堆栈一个数递归调用时,每调用一次其自动型变量就占据堆栈一个区域,供各自的调用使用。递归调用在堆栈中临时占据的区域,供各自的调用使用。递归调用在堆栈中临时占据的存储区域是较多的,在实际运行时,递归调用的时间效率存储区域是较多的,在实际运行时,递归调用的时间效率较差。较差。递归算法

14、在可计算性理论中占有重要地位,它是算法设计递归算法在可计算性理论中占有重要地位,它是算法设计的有力工具,对于拓展编程思路非常有用。就递归算法而的有力工具,对于拓展编程思路非常有用。就递归算法而言并不涉及高深数学知识,只不过初学者要建立起递归概言并不涉及高深数学知识,只不过初学者要建立起递归概念不十分容易。为了建立帮助建立递归的概念,下面以求念不十分容易。为了建立帮助建立递归的概念,下面以求3!为例,给程序编号,以便分析程序的执行过程。图为例,给程序编号,以便分析程序的执行过程。图3.1用图解的方法分解执行过程。用图解的方法分解执行过程。int factorial(int x)/if(x=0)r

15、eturn 1;/else return(x*factorial(x-1);/下面结合图下面结合图3.1,说明执行,说明执行factorial(3)的递归调用过程。的递归调用过程。(1)(1)第第1次执行次执行factorial(3),当执行到,当执行到时,递归时,递归 调用调用factorial(3-2)。(2)执行执行factorial(2),当执行到,当执行到时,递归调用时,递归调用factorial(2-1)(3)(3)执行执行factorial(1),满足语句,满足语句,经,经结束本次结束本次 调用并返回调用并返回1。(4)返回返回继续执行继续执行factorial(2)的语句的语句

16、,执行,执行return 2*1,结束结束factorial(2)。(5)factorial(2)的返回值赋给的返回值赋给factorial(3)的语句的语句,执行,执行return 3*2*1。(6)结束结束factorial(3)的执行,返回值为的执行,返回值为3*2*1=6。由此可见,欲求由此可见,欲求 factorial(3),先要求,先要求 factorial(2);要求;要求 factorial(2)先求先求 factorial(1)。就象剥一颗圆白菜,从外。就象剥一颗圆白菜,从外向里,一层层剥下来,到了菜心,遇到向里,一层层剥下来,到了菜心,遇到 1 的阶乘,其值的阶乘,其值为为

17、1,到达了递归的边界。然后再用,到达了递归的边界。然后再用 factorial(2)=2*factorial(1)得到得到factorial(2),再用,再用factorial(2)的值和公式的值和公式 factorial(3)=3*factorial(2)求得求得factorial(3)。这个过程是使用。这个过程是使用 factorial(n)=n*factorial(n-1)这个普遍公式,从里向外倒推回去得到这个普遍公式,从里向外倒推回去得到 factorial(n)的值。的值。3.2.5 递归与递推的比较递归与递推的比较递推是计算机数值计算中的一个重要算法。思路是通过数递推是计算机数值计

18、算中的一个重要算法。思路是通过数学推导,将复杂的运算化解为若干重复的简单运算,以充学推导,将复杂的运算化解为若干重复的简单运算,以充分发挥计算机长于重复处理的特点。分发挥计算机长于重复处理的特点。1.递推数列的定义递推数列的定义一个数列从某一项起,它的任何一项都可以用它前面的若一个数列从某一项起,它的任何一项都可以用它前面的若干项来确定,这样的数列称为递推数列,表示某项与其前干项来确定,这样的数列称为递推数列,表示某项与其前面的若干项的关系就称为递推公式。例如自然数面的若干项的关系就称为递推公式。例如自然数1,2,n的阶乘就可以形成如下数列:的阶乘就可以形成如下数列:1!,2!,3!,(n-1

19、)!,n!令令fact(n)为为n的阶乘,依据后项与前项的关系可写出递推的阶乘,依据后项与前项的关系可写出递推公式公式 fact(n)=n*fact(n-1)(通项公式)(通项公式)fact(1)=1 (边界条件)(边界条件)2.递推算法的程序实现递推算法的程序实现在有了通项公式和边界条件后,采用循环结构,从边在有了通项公式和边界条件后,采用循环结构,从边界条件出发,利用通项公式通过若干步递推过程就可界条件出发,利用通项公式通过若干步递推过程就可以求出解来。以求出解来。以求阶乘为例。递推是从已知的初始条件出发,逐次以求阶乘为例。递推是从已知的初始条件出发,逐次去求所需要的阶乘值。去求所需要的阶

20、乘值。【例【例3.4】求】求5的阶乘值。的阶乘值。求求5!的初始条件的初始条件fact(1)=1,于是可推得于是可推得 fact(2)=2*fact(1)=2*1=2 fact(3)=3*fact(2)=3*2=6 fact(4)=4*fact(3)=4*6=24 fact(5)=5*fact(4)=5*24=120递推过程相当于从菜心递推过程相当于从菜心“推到推到”外层。外层。/递推求阶乘参考程序递推求阶乘参考程序#include using namespace std;void main()int sum=1,i=0;for(i=2;i=5;i+)sum=i*sum;cout5!=sume

21、ndl;3.递推与递归区别递推与递归区别递推过程相当于从菜心递推过程相当于从菜心“推到推到”外层。递归算法的出发点外层。递归算法的出发点并不放在初始条件上,而放在求解的目标上,从所求的未并不放在初始条件上,而放在求解的目标上,从所求的未知项出发逐次调用本身的求解过程,直到递归的边界(即知项出发逐次调用本身的求解过程,直到递归的边界(即初始条件)。就求阶乘的例子而言,读者会认为递归算法初始条件)。就求阶乘的例子而言,读者会认为递归算法可能是多余的,费力不讨好。但许多实际问题不可能或不可能是多余的,费力不讨好。但许多实际问题不可能或不容易找到显而易见的递推关系,这时递归算法就表现出了容易找到显而易

22、见的递推关系,这时递归算法就表现出了明显的优越性。它比较符合人的思维方式,逻辑性强,可明显的优越性。它比较符合人的思维方式,逻辑性强,可将问题描述得简单扼要,具有良好的可读性,易于理解。将问题描述得简单扼要,具有良好的可读性,易于理解。许多看来相当复杂,或难以下手的问题,如果能够使用递许多看来相当复杂,或难以下手的问题,如果能够使用递归算法,就会使问题变得易于处理。归算法,就会使问题变得易于处理。【例【例3.5】A、B、C、D、E合伙夜间捕鱼,凌晨时都疲惫合伙夜间捕鱼,凌晨时都疲惫不堪,各自在河边的树丛中找地方睡着了。日上三竿,不堪,各自在河边的树丛中找地方睡着了。日上三竿,A第一个醒来,他将

23、鱼平分作第一个醒来,他将鱼平分作5份,把多余的一条扔回湖中,份,把多余的一条扔回湖中,拿自己的一份回家去了;拿自己的一份回家去了;B第二个醒来,也将鱼平分作第二个醒来,也将鱼平分作5份,扔掉多余的一条,只拿走自己的一份;接着份,扔掉多余的一条,只拿走自己的一份;接着C、D、E依次醒来,也都按同样的办法分鱼。问依次醒来,也都按同样的办法分鱼。问5人至少合伙捕人至少合伙捕到多少条鱼?每个人醒来后看到的鱼数是多少条?到多少条鱼?每个人醒来后看到的鱼数是多少条?使用递推的解题思路如下:使用递推的解题思路如下:假定假定A、B、C、D、E 5人的编号分别为人的编号分别为1、2、3、4、5,为了容易理解,让

24、整数数组的标号直接与这为了容易理解,让整数数组的标号直接与这5个人的序号个人的序号对应,定义整数数组对应,定义整数数组fish6。不使用。不使用fish0,从而可以使,从而可以使用数组用数组fishk表示第表示第k个人所看到的鱼数。个人所看到的鱼数。fish1表示表示A所看到的鱼数所看到的鱼数,fish2表示表示B所看到的鱼数所看到的鱼数。显然有。显然有如下关系:如下关系:fish1=5人合伙捕鱼的总鱼数人合伙捕鱼的总鱼数fish2=(fish1-1)*4/5fish3=(fish2-1)*4/5fish4=(fish3-1)*4/5fish5=(fish4-1)*4/5由此可以写出如下的一般

25、表达式:由此可以写出如下的一般表达式:fishi=(fishi-1-1)*4/5 i=2,3,4,5这个公式可用于从已知这个公式可用于从已知A看到的鱼数去推算看到的鱼数去推算B看到的,再看到的,再推算推算C看到的,看到的,。现在要求的是。现在要求的是A看到的,能否倒过看到的,能否倒过来,先知来,先知E看到的再反推看到的再反推D看到的,看到的,直到,直到A看到的。看到的。为此将上式改写为为此将上式改写为 fishi-1=fishi*5/4+1 i=5,4,3,2分析上式如下:分析上式如下:当当i=5时,时,fish5表示表示E醒来后看到的鱼数,该数应满醒来后看到的鱼数,该数应满足被足被5整除后余

26、整除后余1,即,即fish5%5=1 当当i=5时时,fishi-1 表示表示D醒来后看到的鱼数,该数既要醒来后看到的鱼数,该数既要满足满足fish4=fish5*5/4+1,又要满足,又要满足fish4%5=1。显。显然,然,fish4不能不是整数,这个结论通样可以用于不能不是整数,这个结论通样可以用于fish3,fish2,和,和fish1。按按题意要求题意要求5人合伙捕到的最少鱼数,可以从小往大枚人合伙捕到的最少鱼数,可以从小往大枚举,可先让举,可先让E所看到的鱼数最少为所看到的鱼数最少为6条,即条,即fish5初始化初始化为为6来试,之后每次增加来试,之后每次增加5再试,直至递推到再试

27、,直至递推到fish1且所且所得整数除以得整数除以5之后的鱼数为之后的鱼数为1。根据上述思路,可以将程。根据上述思路,可以将程序分为序分为3个部分:程序准备个部分:程序准备(包括声明和初始化包括声明和初始化)部分、递部分、递推部分和输出结果部分。推部分和输出结果部分。程序准备部分包含定义数组程序准备部分包含定义数组fish6并初始化为并初始化为1,定义循,定义循环控制变量环控制变量i并初始化为并初始化为0。输出结果部分就是输出计算结。输出结果部分就是输出计算结果。以上两个部分都很简单,下面着重介绍递推部分的实果。以上两个部分都很简单,下面着重介绍递推部分的实现方法。现方法。递推部分使用递推部分

28、使用do while直到型循环结构,其循环体又直到型循环结构,其循环体又含两块:含两块:(1)枚举枚举过程中的过程中的fish5的初值设置,一开始的初值设置,一开始fish5=1+5;以后每次增以后每次增5。也就是说,第。也就是说,第1个边界条件是个边界条件是fish=6,以,以后的边界条件是每次递增后的边界条件是每次递增5。(2)使用使用一个一个for循环,循环,i的初值为的初值为4,终值为,终值为1,步长为,步长为-1,该循环的循环体是一个分支语句,如果该循环的循环体是一个分支语句,如果fishi+1不能被不能被4整除,则跳出整除,则跳出for循环(使用循环(使用break语句);否则,从

29、语句);否则,从fishi+1算出算出fishi。当由。当由break语句让程序退出循环时,语句让程序退出循环时,意味着某人看到的鱼数不是整数,当然不是所求,必须令意味着某人看到的鱼数不是整数,当然不是所求,必须令fish5加加5后再试,即重新进入直到型循环后再试,即重新进入直到型循环do while的的循环体。当正常退出循环体。当正常退出for循环时,一定是循环控制变量循环时,一定是循环控制变量i从从初值初值4,一步一步执行到终值,一步一步执行到终值1,每一步的鱼数均为整数;,每一步的鱼数均为整数;最后最后i=0,表示计算完毕,且也达到了退出直到型循环的,表示计算完毕,且也达到了退出直到型循

30、环的条件。条件。/捕鱼问题参考程序捕鱼问题参考程序#include /预编译命令预编译命令using namespace std;void main()int fish6=1,1,1,1,1,1;/记录每人醒来后记录每人醒来后 /看到的鱼数看到的鱼数 int i=0;do fish5=fish5+5;/让让E看到的鱼数增看到的鱼数增5 for(i=4;i=1;i-)if(fishi+1%4!=0)break;/跳出跳出for循环循环elsefishi=fishi+1*5/4+1;/计算第计算第i人人 /看到的鱼数看到的鱼数 while(i=1);/当当i=1,继续做继续做do循环循环/输出计算

31、结果输出计算结果for(i=1;i=5;i+)cout“第第”i“个人看到的鱼是个人看到的鱼是”fishi条。条。endl;程序运行的输出结果如下:程序运行的输出结果如下:第第1个人看到的鱼是个人看到的鱼是3121条。条。第第2个人看到的鱼是个人看到的鱼是2496条。条。第第3个人看到的鱼是个人看到的鱼是1996条。条。第第4个人看到的鱼是个人看到的鱼是1596条。条。第第5个人看到的鱼是个人看到的鱼是1276条。条。3.3 函数参数的传递方式函数参数的传递方式函数参数的传递方式有函数参数的传递方式有3种:传值、传地址和传引用。函种:传值、传地址和传引用。函数的参数还可以设计成默认形式,以方便

32、使用。数的参数还可以设计成默认形式,以方便使用。3.3.1 传值传值传值是将实参的值传递给形参,形参拥有实参的一个备份,传值是将实参的值传递给形参,形参拥有实参的一个备份,当在函数中改变形参的值时,改变的是这个备份中的值,当在函数中改变形参的值时,改变的是这个备份中的值,不会影响原来实参的值。传值方式可以防止被调用函数改不会影响原来实参的值。传值方式可以防止被调用函数改变参数的原始值,这在很多场合是很重要的。变参数的原始值,这在很多场合是很重要的。著名的著名的swap函数充分地说明了传值和传址的区别。以交函数充分地说明了传值和传址的区别。以交换两个整数为例,下面是传值的换两个整数为例,下面是传

33、值的swap函数和测试程序:函数和测试程序:【例【例3.6】传值不会改变原来值的例子。】传值不会改变原来值的例子。#include#include using namespace std;void swap(string,string);/函数参数采用传值方式函数参数采用传值方式void main()string str1(现在现在),str2(过去过去);swap(str1,str2);/传值传值 cout返回后:返回后:str1=str1 str2=str2endl;void swap(string s1,string s2)string temp=s1;s1=s2;s2=temp;cou

34、t交换为:交换为:str1=s1 str2=s2endl;虽然虽然swap函数内交换函数内交换str1和和str2的值,但不影响原来的的值,但不影响原来的值,所以程序输出结果如下:值,所以程序输出结果如下:交换为:交换为:str1=过去过去 str2=现在现在返回后:返回后:str1=现在现在 str2=过去过去直接使用一般的数据类型的对象,或者使用类和结构的直接使用一般的数据类型的对象,或者使用类和结构的对象作为参数,均是传值方式。注意,数组不能使用传对象作为参数,均是传值方式。注意,数组不能使用传值方式。值方式。3.3.2 传地址传地址传地址又简称传址,它传递的是指向参数的指针。实传地址又

35、简称传址,它传递的是指向参数的指针。实际上,形参传递的就是实参本身,当在函数中改变形际上,形参传递的就是实参本身,当在函数中改变形参的值时,改变的就是原来实参的值。大多数程序设参的值时,改变的就是原来实参的值。大多数程序设计者为提高运行效率,常使用传址方式。例如传递类计者为提高运行效率,常使用传址方式。例如传递类或结构时,传递对象的地址。指针可以指向对象的地或结构时,传递对象的地址。指针可以指向对象的地址,所以传址要用到指针。数组名就是指针名,所以址,所以传址要用到指针。数组名就是指针名,所以数组只能用传址方式。数组只能用传址方式。【例【例3.7】传地址改变原来值的例子。】传地址改变原来值的例

36、子。#include#include using namespace std;void swap(string*,string*);/函数参数采用传址方式函数参数采用传址方式void main()string str1(现在现在),str2(过去过去);swap(&str1,&str2);/传址传址 cout返回后:返回后:str1=str1 str2=str2endl;void swap(string*s1,string*s2)string temp=*s1;*s1=*s2;*s2=temp;cout交换为:交换为:str1=*s1 str2=*s2endl;因为实参与形参的地址相同,所以改

37、变形参就是改变实参。因为实参与形参的地址相同,所以改变形参就是改变实参。输出结果如下:输出结果如下:交换为交换为 str1=过去过去 str2=现在现在返回后返回后 str1=过去过去 str2=现在现在注意:不要一定要在主程序里产生指针,然后再用指针作注意:不要一定要在主程序里产生指针,然后再用指针作为参数。函数原型参数的类型是指针,可以直接让它指向为参数。函数原型参数的类型是指针,可以直接让它指向对象地址,即对象地址,即 string*s1=&str1;是完全正确的,所以使用是完全正确的,所以使用&str1直接作为参数即可。直接作为参数即可。【例【例3.8】传递数组名实例。】传递数组名实例

38、。#include using namespace std;void swap(int);/数组原型使用数组原型使用类型类型 的形式的形式void main()int a=3,8;swap(a);/传递数组名传递数组名 cout返回后返回后:a=a0 b=a1endl;void swap(int a)int temp=a0;a0=a1;a1=temp;cout交换为交换为:a=a0 b=a1endl;运行结果如下:运行结果如下:交换为:交换为:a=8 b=3返回后:返回后:a=8 b=33.3.3 传引用方式传引用方式C+提供引用,主要是用来建立函数参数的引用传递方提供引用,主要是用来建立函数

39、参数的引用传递方式。在说明引用参数时,不需提供初始值,其初始值在式。在说明引用参数时,不需提供初始值,其初始值在函数调用时由实参提供。传引用是将对象的引用作为参函数调用时由实参提供。传引用是将对象的引用作为参数传递,引用和被引用对象的地址一样,所以改变形参数传递,引用和被引用对象的地址一样,所以改变形参就是改变实参。就是改变实参。【例【例3.9】通过传引用改变原来值的例子。】通过传引用改变原来值的例子。#include#include using namespace std;void swap(string&,string&);/函数参数采用函数参数采用 /传引用方式传引用方式void mai

40、n()string str1(现在现在),str2(过去过去);swap(str1,str2);/传引用传引用 cout返回后:返回后:str1=str1 str2=str2endl;void swap(string&s1,string&s2)string temp=s1;s1=s2;s2=temp;cout交换为:交换为:str1=s1 str2=s2endl;当程序中调用函数当程序中调用函数swap时,实参时,实参str1和和str2分别初始化分别初始化引用引用s1和和s2,所以在函数,所以在函数swap中,中,s1和和s2分别引用分别引用str1和和str2,对,对s1和和s2的访问就是

41、对的访问就是对str1和和str2的访问,的访问,所以函数所以函数swap改变了改变了main 函数中变量函数中变量str1和和str2的值。的值。通过使用引用参数,一个函数可以修改另一个函数内的通过使用引用参数,一个函数可以修改另一个函数内的变量。变量。程序输出如下:程序输出如下:交换为:交换为:str1=过去过去 str2=现在现在返回后:返回后:str1=过去过去 str2=现在现在 也可以改为传递结构对象的引用,其效果一样。如果使也可以改为传递结构对象的引用,其效果一样。如果使用数组,参见【例用数组,参见【例1.7】间接引用数组的方法。】间接引用数组的方法。因为传引用比传指针更好,所以

42、因为传引用比传指针更好,所以C+建议使用传引用的建议使用传引用的方式。方式。【例【例3.10】求求10个学生成绩的平均值,并统计其中不及个学生成绩的平均值,并统计其中不及格的人数。要求用一个函数实现,并返回这两个数据给调格的人数。要求用一个函数实现,并返回这两个数据给调用函数,并且函数的形参使用引用来实现。用函数,并且函数的形参使用引用来实现。#includeusing namespace std;typedef double array12;void avecount(array&b,int n)double ave(0);int count(0);/累加器初始化累加器初始化0 for(in

43、t j=0;jn-2;j+)ave=ave+bj;if(bj60)count+;bn-2=ave/(n-2);/填入平均成绩填入平均成绩 bn-1=count;/填入不及格人数填入不及格人数void main()array b=12,34,56,78,90,98,76,85,64,43;array&a=b;avecount(a,12);/调用函数计算统计调用函数计算统计 cout“平均成绩为平均成绩为”a10“分分,不及格人数有不及格人数有”int(a11)人。人。endl;程序输出:平均成绩为程序输出:平均成绩为61.8分分,不及格人数有不及格人数有5人。人。3.3.4 默认参数默认参数C+

44、语言在函数调用时,引进了一种新类型的参数:默语言在函数调用时,引进了一种新类型的参数:默认参数。默认参数就是不要求程序员设定该参数,而由认参数。默认参数就是不要求程序员设定该参数,而由编译器在需要时给该参数赋默认值。当程序员需要传递编译器在需要时给该参数赋默认值。当程序员需要传递特殊值时,必须显式地指明。默认参数是在函数原型中特殊值时,必须显式地指明。默认参数是在函数原型中说明的。默认参数可以多于说明的。默认参数可以多于1个,但必须放在参数序列个,但必须放在参数序列的后部,例如:的后部,例如:int SaveName(char*first,char*second=,char*third=,ch

45、ar*fourth=);这种方式表明在实际调用函数这种方式表明在实际调用函数SaveName时,如果不给时,如果不给出参数出参数second、third和和fourth,则取默认值。如果一,则取默认值。如果一个默认参数需要指明一个特定值,则在其之前的所有参个默认参数需要指明一个特定值,则在其之前的所有参数都必须赋值。在上例中,如果需给出参数数都必须赋值。在上例中,如果需给出参数third的值,的值,则必须同时也给则必须同时也给first和和second赋值,例如:赋值,例如:int status=SaveName(Alpha,Bravo,Charlie);【例【例3.11】设计一个根据参数数量

46、输出信息的函数。】设计一个根据参数数量输出信息的函数。#include#include using namespace std;void Display(string s1,string s2=,string s3=);void main()string str1(现在现在),str2(过去过去),str3(将来将来);Display(str1);Display(str1,str2,str3);Display(str3,str1);Display(str2,str3);void Display(string s1,string s2,string s3)if(s2=&s3=)couts1end

47、l;else if(s3=&s2!=)couts1、s2endl;else couts1、s2、s3endl;输出结果如下:输出结果如下:现在现在现在、过去、将来现在、过去、将来将来、现在将来、现在过去、将来过去、将来3.3.5 使用使用const保护数据保护数据用用const修饰传递参数,意思是通知函数,它只能使用参修饰传递参数,意思是通知函数,它只能使用参数而无权修改它。这主要是为了提高系统的自身安全。数而无权修改它。这主要是为了提高系统的自身安全。C+中普遍采用这种方法。中普遍采用这种方法。【例【例3.12】不允许改变作为参数传递的字符串内容的实例】不允许改变作为参数传递的字符串内容的实

48、例#include#include using namespace std;void change(const string&);void main()string str(Can you change it?);change(str);coutstrendl;void change(const string&s)string s2=s+No!;couts2endl;参数传递使用参数传递使用const修饰,程序输出如下:修饰,程序输出如下:Can you change it?No!/函数内不能修改,只能使用函数内不能修改,只能使用Can you change it?/原内容不变原内容不变3.4

49、 深入讨论函数返回值深入讨论函数返回值C+函数的返回值类型可以是除数组和函数以外的任何类函数的返回值类型可以是除数组和函数以外的任何类型。定义一个函数,要正确选择函数返回值。非型。定义一个函数,要正确选择函数返回值。非void类型类型的函数必须向调用者返回一个值。该值可以是标量对象,的函数必须向调用者返回一个值。该值可以是标量对象,也可以是复合对象。标量对象指那些声明为基本类型的对也可以是复合对象。标量对象指那些声明为基本类型的对象,返回值置于寄存器中。数组只能返回地址。复合对象象,返回值置于寄存器中。数组只能返回地址。复合对象是指结构或类的对象。返回类对象的情况将在第是指结构或类的对象。返回

50、类对象的情况将在第5章介绍。章介绍。返回结构类型对象时,是逐个字节地拷贝过来的。返回结构类型对象时,是逐个字节地拷贝过来的。当函数返回值是指针或引用对象时,需要特别注意:函数当函数返回值是指针或引用对象时,需要特别注意:函数返回所指的对象必须继续存在,因此不能将函数内的局部返回所指的对象必须继续存在,因此不能将函数内的局部对象作为函数的返回值。对象作为函数的返回值。虽然在虽然在C+中允许返回一个指向局部静态对象的指针或引中允许返回一个指向局部静态对象的指针或引用,但最好不要这样做。用,但最好不要这样做。3.4.1 返回引用的函数返回引用的函数函数可以返回一个引用,将函数说明为返回一个引用的主函

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 办公、行业 > 项目策划与方案类
版权提示 | 免责声明

1,本文(C++函数和函数模板详解.ppt)为本站会员(hwpkd79526)主动上传,163文库仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。
2,用户下载本文档,所消耗的文币(积分)将全额增加到上传者的账号。
3, 若此文所含内容侵犯了您的版权或隐私,请立即通知163文库(发送邮件至3464097650@qq.com或直接QQ联系客服),我们立即给予删除!


侵权处理QQ:3464097650--上传资料QQ:3464097650

【声明】本站为“文档C2C交易模式”,即用户上传的文档直接卖给(下载)用户,本站只是网络空间服务平台,本站所有原创文档下载所得归上传人所有,如您发现上传作品侵犯了您的版权,请立刻联系我们并提供证据,我们将在3个工作日内予以改正。


163文库-Www.163Wenku.Com |网站地图|