c程序设计第三章函数和函数模板课件_第1页
c程序设计第三章函数和函数模板课件_第2页
c程序设计第三章函数和函数模板课件_第3页
c程序设计第三章函数和函数模板课件_第4页
c程序设计第三章函数和函数模板课件_第5页
已阅读5页,还剩46页未读 继续免费阅读

下载本文档

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

文档简介

第三章函数和函数模板在面向对象程序设计中,成员函数也是函数,所以本节关于函数的讨论,也适合类的成员函数。正确设计函数原型和参数类型,不仅能保证函数的真确性,而且能提高程序设计的效率。本章除了介绍选择函数参数和函数返回值等问题之外,还将讨论内联函数、函数重载和函数模板等内容。3.1函数的参数及其传递方式C++中函数的参数有两种传递方式:传值和传引用。传引用就是传对象的地址,所以也称传地址方式。一、对象做函数参数将对象作为函数参数,是将实参对象的值传递给形参对象,形参拥有实参的备份。这种传递是单向的。当在函数中改变形参的值时,改变的是这个备份中的值,不会影响原来实参的值。例题:分析以下程序的结果(lt3_1.cpp)#include<iostream>#include<string>#include<algorithm>usingnamespacestd;voidstrsort(string);voidmain(){ strings="China"; cout<<"原字符串为:"<<s<<endl; strsort(s); cout<<"变化后的字符串为:"<<s<<endl;}voidstrsort(stringc){ sort(c.begin(),c.end());}二、对象指针作为函数参数将指向对象的指针作为函数参数,形参是对象指针,实参是对象的地址值。因为实参和形参的地址相同,所以改变形参就是改变实参。请分析以下程序的结果(lt3_2.cpp)#include<iostream>#include<string>usingnamespacestd;voidstrswap(string,string);voidmain(){ strings1="China",s2("beijing"); cout<<"原字符串为:s1:"<<s1<<",s2:"<<s2<<endl;

strswap(s1,s2); cout<<"交换后的字符串为:s1:"<<s1<<",s2:"<<s2<<endl;}voidstrswap(stringc1,stringc2){

c1.swap(c2);}&&***()***实参是对象形参是对象实参是对象的地址值形参是对象指针例题:请分析以下程序的结果(lt3_3.cpp)#include<iostream>#include<string>#include<algorithm>usingnamespacestd;voidstrsort(string*c,intn);voidmain(){strings[]={"China","Beijing","Jinan"};inti;cout<<"原字符串为:"<<endl;for(i=0;i<3;i++)cout<<s[i]<<endl;strsort(s,3);cout<<"反转后的字符串为:"<<endl;for(i=0;i<3;i++)cout<<s[i]<<endl;}voidstrsort(string*c,intn){ for(inti=0;i<n;i++) reverse(c[i].begin(),c[i].end());}请分析以下程序的结果(lt3_4.cpp)#include<iostream>#include<string>usingnamespacestd;voidstrswap(string,string);voidmain(){ strings1="China",s2("beijing"); cout<<"原字符串为:s1:"<<s1<<",s2:"<<s2<<endl; strswap(s1,s2); cout<<"交换后的字符串为:s1:"<<s1<<",s2:"<<s2<<endl;}voidstrswap(stringc1,stringc2){ c1.swap(c2);}对象做函数参数&&&&引用做函数参数#include<iostream>#include<string>usingnamespacestd;voidstrs*,string*);voidmain(){ strings1="China",s2("beijing"); cout<<"原字符串为:s1:"<<s1<<",s2:"<<s2<<endl; strswap(&s1,&s2); cout<<"交换后的字符串为:s1:"<<s1<<",s2:"<<s2<<endl;}voidstrs*c1,string*c2){ (*c1).swap(*c2);}指针做函数参数四、默认参数默认参数可以多于1个,但必须放在参数序列的后部。在函数调用时,如果一个默认参数需要指明一个特定值,则在其之前的所有参数都必须赋值。因为系统是按从左到右的顺序将实参与形参结合,当实参的数目不足时,系统将按同样的顺序用声明中或定义中的默认值来补齐所缺少的参数。C++允许在定义函数时给其中的某个或某些形式参数指定默认值,这样,当发生函数调用时,如果省略了对应位置上的实参的值时,则在执行被调函数时,以该形参的默认值进行运算。当程序员需要传递特殊值时,必须显式地指明。默认参数一般在函数说明中提供。如果程序中既有函数的说明又有函数的定义时,则定义函数时不允许再定义参数的默认值。如果程序中只有函数的定义,而没有说明函数,则默认参数才可出现在函数定义中。#include<iostream>#include<string>usingnamespacestd;voiddisplay(intx,inty);voidmain(){ inta=3,b=5; display(a,b);

}voiddisplay(intx,inty){ cout<<x<<","<<y<<endl;}display(a);display();=0=0错误练习:若有函数的声明如下:voidmal(inta,intb=3,intc=5);

判断以下函数调用的正误:

mal(3,,9)

mal(3);

mal(3,5);

mal(3,8,9);

mal()

√√√XX//请分析以下程序的运行结果(lt3_6.cpp)#include<iostream>#include<string>usingnamespacestd;voiddisplay(strings1,strings2="",strings3="");voidmain(){ strings1("现在"),s2("过去"),s3("将来"); display(s1); display(s1,s2,s3); display(s3,s1); display(s2,s3);}voiddisplay(strings1,strings2,strings3){ if(s2==""&&s3=="")cout<<s1<<endl; elseif(s3==""&&s2!="")cout<<s1<<"、"<<s2<<endl; elsecout<<s1<<"、"<<s2<<"、"<<s3<<endl;}五、用const保护数据用const修饰传递参数,意义在于通知函数,它只能使用参数而无权修改它。课本65页:改错题:3题编程题:2、4题作业课程回顾1.在函数调用时,如某一默认参数要指明一个特定值,则有()(2008.10)A.其之前所有参数都必须赋值 B.其之后所有参数都必须赋值C.其前、后所有参数都必须赋值 D.其前、后所有参数都不必赋值2.函数默认参数在函数原型中说明,默认参数必须放在参数序列的()(2009.1)A.前部 B.中部C.后部 D.两端AC3.2深入讨论函数返回值c++函数的返回值类型可以是除了数组和函数以外的任何类型。非void类型的函数必须向调用者返回一个值。当函数返回值是指针或者引用对象时,需要注意的是:函数返回值所指的对象必须继续存在,因此不能将函数内部的局部对象作为函数的返回值。#include<iostream>//分析程序结果(lt3_8a.cpp)usingnamespacestd;classA{ intx;public: A(inta=0){x=a;} voidset(inty){x=y;}

int&f(){returnx;} voiddisp(){cout<<"x:"<<x<<endl;}};voidmain(){ Aa; a.disp(); a.set(1); a.disp();

a.f()=2; a.disp();}通过返回引用的成员函数使用类的私有成员二、返回指针的函数函数的返回值可以是存储某种类型数据的内存地址,称这种函数为指针函数。定义的一般形式:类型标识符*函数名(参数列表)练习:定义一个input函数,该函数可以输入一组float型数据,并将头指针返回:float*input(int&n){}cout<<"请输入数据的个数:";cin>>n;if(n<=0)returnNULL;=newfloat[n];if(buf==0)returnNULL;for(inti=0;i<n;i++)cin>>buf[i];return思考:如何开辟n个float型的空间,并将头指针赋值给变量buffloat*buf思考:如何通过键盘输入给这n个空间赋值?buf;cout<<"请输入"<<n<<"个数据:"<<endl;或者*(buf+i)思考:如何将头指针返回?三、返回对象的函数#include<iostream>//lt3_10.cpp#include<string>usingnamespacestd;stringinput(int);voidmain(){ intn; cout<<"请输入单词的个数:"; cin>>n; strings=input(n); cout<<s;}stringinput(intn){ strings1,s2; for(inti=0;i<n;i++) {cin>>s1; s2=s2+s1+"";} returns2;}四、函数返回值做函数参数//请分析以下程序的结果(lt3_11.cpp)#include<iostream>usingnamespacestd;intmax(int,int);voidmain(){ intx=2,y=8,z=5,m;

m=(max(x,y),z); cout<<m<<endl;}intmax(inta,intb){if(a>b)returna;elsereturnb;}注:如果用函数返回值作为另一个函数的参数,这个返回值必须与参数的类型一致。3.5函数重载和默认参数函数重载可以使一个函数名具有多种功能,即具有多种形态,称这种特性为

。多态性#include<iostream>usingnamespacestd;intmax(int,int);doublemax(double,double);charmax(char,char);intmax(int,int,int);voidmain(){cout<<max(5,8)<<endl;cout<<max(3.6,5.8)<<endl;cout<<max('a','A')<<endl;cout<<max(12,65,78)<<endl;}intmax(inta,intb){if(a>b)returna;elsereturnb;}doublemax(doublea,doubleb){if(a>b)returna;elsereturnb;}charmax(chara,charb){if(a>b)returna;elsereturnb;}intmax(inta,intb,intc){if(max(a,b)>c)returnmax(a,b);elsereturnc;}由上可知,当函数的参数类型不同,或者参数个数不同时,函数可以重载。仅有函数返回值不同不能区分重载函数。//分析以下程序的结果(lt3_13a.cpp)#include<iostream>usingnamespacestd;intadd(int,int);intadd(int,int,int);voidmain(){ inta=3,b=5,c=6,sum; sum=add(a,b); cout<<sum<<endl; sum=add(a,b,c); cout<<sum<<endl;}intadd(intx,inty){ returnx+y;}intadd(intx,inty,intz){ returnx+y+z;}函数的重载z=0函数的默认参数注意:函数重载和默认参数可同时使用。若已定义默认参数函数,则不能重载参数类型相同,参数个数少于默认参数个数的函数。3.5函数模板有些函数重载时参数个数相同,只是类型不同,此时重载函数比较繁琐,可利用函数模板实现。intmax(inta,intb){if(a>b)returna;elsereturnb;}doublemax(doublea,doubleb){if(a>b)returna;elsereturnb;}charmax(chara,charb){if(a>b)returna;elsereturnb;}编制这些函数所提供的程序文本完全相同!比较这三个函数的异同!处理的数据类型不同!Tmax(Ta,Tb){if(a>b)returna;elsereturnb;}intmax(inta,intb){if(a>b)returna;elsereturnb;}doublemax(doublea,doubleb){if(a>b)returna;elsereturnb;}charmax(chara,charb){if(a>b)returna;elsereturnb;}如果把其中的类型名称抽象出来用一个符号(比如T)来表示,则有如下的抽象形式:函数模板TTTTTTTTT一、函数模板很多情况下,设计的函数可以处理多种数据类型,但是即使设计为函数重载也只是使用相同的函数名,函数仍然要分别定义。函数模板之所以能以同样的程序代码对不同类型的数据进行处理,其关键是将所处理的数据类型声明为参数,即类型参数化。函数重载通常基于不同的数据类型实现类似的操作,而对不同数据类型的操作完全相同,用函数模板更为简洁方便。

函数模板是对一组函数的描述,它不是一个真实的函数,编译系统并不产生任何执行代码。当编译系统在程序中发现有与函数模板中相匹配的函数调用时,便生成一个重载函数,该重载函数的函数体与函数模板的函数体相同,该重载函数就是模板函数。1、声明函数模板一般格式:template类型形参表返回类型函数名(形参表){函数体}例如:Tmax(Ta,Tb){if(a>b)returna;elsereturnb;}注:“类型形参表”可以包含基本数据类型,也可以包含类类型。类型形参需要加前缀class或者typename。如果类型形参多于一个,则每个类型形参都需要使用class或者typename。template<classT>模版以template关键字和一个形参表开头。2、编写函数模板编写函数模板的一般方式如下:(1)定义一个普通的函数,数据类型采用具体的普通的数据类型。如求两个整数中的较大者:intmax(inta,intb){if(a>b)returna;elsereturnb;}(2)将数据类型参数化,将其中具体的数据类型名(如int)全部替换成由自己定义的抽象的类型参数名(如T),Tmax(Ta,Tb){if(a>b)returna;elsereturnb;}(3)在函数头钱用关键字template引出对类型参数名的声明。这样就把一个具体的函数改造成了一个通用的函数模板。Tmax(Ta,Tb){if(a>b)returna;elsereturnb;}template<classT>模板(template)把函数或类要处理的数据类型参数化,表现为参数的多态性。模板用于表达逻辑结构相同,且具体数据元素类型不同的数据对象的通用行为,从而使得程序可以从逻辑功能上抽象,把被处理的对象(数据)类型作为参数传递。C++提供了两种模板机制:函数模板和类模板(第七章)。在声明了一个函数模板后,当编译系统发现有一个对应的函数调用时,将根据实参中的类型来确认是否匹配函数模板中对应的类型形参,然后生成一个重载函数。该重载函数的定义体与函数模板中的函数定义体相同,称之为模板函数(templatefunction)。函数模板与模板函数的区别是:函数模板是一个模板,其中用到通用类型参数,不能直接执行。模板函数是一个具体的函数,它由编译系统在遇到具体函数调用时所生成,具有程序代码,可以执行。#include<iostream>usingnamespacestd;template<classT>Tmax(Ta,Tb){ if(a>b)returna; elsereturnb;}voidmain(){ intm1; doublem2; charm3; m1=max<int>(3,8); m2=max<double>(3.6,12.5); m3=max<char>('a','A'); cout<<m1<<","<<m2<<","<<m3<<endl;}在调用函数模板时,函数参数的类型决定到底使用模板的哪个版本。也就是说,模板的参数是由有数的参数推断出来的。

1.一个函数功能不太复杂,但要求被频繁调用,选用()A.内联函数B.重载函数C.递归函数D.嵌套函数内2.下列哪个类型函数不适合声明为内联函数()A.函数体语句较多B.函数体语句较少C.函数执行时间较短D.函数执行时间过长AA课程回顾3.下列关于函数的重载说法正确的是()(A)重载函数必须具有不同的返回值类型(B)重载函数形参个数必须不同(C)重载函数必须具有不同的形参列表(D)重载函数名可以不同C4.包含哪种语句的函数不能声明为内联函数()A.循环 B.变量自增自减C.if...else… D.变量声明A5.intFunc(int,int);不可与下列哪个函数构成重载()(2008.10)A.intFunc(int,int,int);B.doubleFunc(int,int);C.doubleFunc(double,double);D.doubleFunc(int,double);B6.联函数的特点是()A.减少代码量,加快访问速度 B.减少代码量,减缓访问速度C.增加代码量,减缓访问速度 D.增加代码量,加快访问速度C7.声明函数为内联函数时所使用的关键字为(

)A.const

B.inlineC.short

D.signedB8.在下划线处填上缺少的部分。源程序如下(2009.1)#include<iostream>usingnamespacestd;________Tfun(Tx){______y;y=x*x-T(5);

returny;

}voidmain(){floata=2;cout<<fun(a);}template<classT>T3、使用函数模板函数模板是不能直接执行的,需要实例化为模板函数后才能执行。使用格式:模板函数名<类型参数>(实参表)或者:模板函数名(实参表)显式比较准则默认方式当编译系统发现有一个函数调用时,c++将根据“实参表”中的类型生成一个重载函数即模板函数。该模板函数的定义体与函数模板的函数定义体相同,而“形参表”的类型则以“实参表”的实际类型为依据。如有函数模板如下:template<classT>Tmax(Ta,Tb){ if(a>b)returna; elsereturnb;}m1=max<int>(3,8);m2=max<double>(3.6,12.5);m3=max<char>('a','A');m1=max(3,8);m2=max(3.6,12.5);m3=max('a','A');或者则对该函数模板的使用有:m4=max<char>('a','A');m4=max(97,'A');error:templateparameter'T'isambiguousX√m4=max(char(97),'A');m4=max(97,int('A‘));√√注:要想省去显式调用的麻烦,条件是由这个调用的函数参数表能够惟一地去标识出模板参数的一个集合。练习:利用函数模板设计一个求两个数之和的函数,并检验之。template<classT>Tsum(Tn1,Tn2){ return(n1+n2);}voidmain(){ cout<<sum(3,5)<<endl;cout<<sum(3.3,9.9)<<endl;}5、重载函数模板函数模板与重载是密切相关的。实际上,从函数模板产生的相关函数都是同名的,因此c++编译系统采用重载的解决方法调用相应函数。函数模板本身可以用多种方式重载,这需要提供其他函数模板,制定不同参数的相同函数名。(lt3_17.cpp)函数模板也可以用其他非模板函数(同名而参数不同)重载。(lt3_18.cpp)Tmax(Ta,Tb){ if(a>b)returna; elsereturnb;}练习1:利用函数模板设计一个求两个数中较大者的函数。练习2:利用函数模板设计一个求三个数中较大者的函数。template<classT>Tmax(Ta,Tb,Tc){Tm; if(a>b)m=a; elsem=b; if(c>m)m=c; returnm;

}#include<iostream>usingnamespacestd;template<classT>Tmax(Ta,Tb){ if(a>b)returna; elsereturnb;}template<classT>Tmax(Ta,Tb,Tc){Tm; if(a>b)m=a; elsem=b; if(c>m)m=c; returnm;

}voidmain(){cout<<max(5,6,8)<<endl;cout<<max(6.8,12.5)<<endl;}函数模板的重载#include<iostream.h>template<classT>Tmax(Tx,Ty){cout<<"模板函数:max=";return(x>y)?x:y;}intmax(intx,inty,intz=0){intm;cout<<"int重载函数:max=";if(z==0)return(x>y)?x:y;else{m=(x>y)?x:y;return(m>z)?m:z;}}charmax(charx,chary){cout<<"char重载函数:max=";return(x>y)?x:y;}voidmain(){cout<<max(3,6)<<endl;cout<<max(3,6,9)<<endl;cout<<max('a','c')<<endl;cout<<max(3.6,5.9)<<endl;}练习1:利用函数模板设计一个求两个数之和的函数模板sum.template<classT>Tsum(Tn1,Tn2){ return(n1+n2);}练习2:编写一个求两个字符串之和的函数sumstring

温馨提示

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

评论

0/150

提交评论