第20讲模板 教学目的与要求: 了解模板的功能和作用。 掌握函数模板和类模板的声明和使用。 教学内容提要 函数模板; 2、函数模板参数; 3、类模板; 教学重点:函数模板和类模板的声明和使用 教学难点:函数模板的申明和使用。 教学进度:P222~P238 教学过程:
第 20 讲 模板 •教学目的与要求: 了解模板的功能和作用。 掌握函数模板和类模板的声明和使用。 •教学内容提要: 1、函数模板; 2、函数模板参数; 3、类模板; •教学重点: 函数模板和类模板的声明和使用。 •教学难点: 函数模板的申明和使用。 •教学进度:P222~P238 •教学过程:
所谓模板是一种使用无类型参数来产生一系列函数或类的机制,是C的 个重要特性。它的实现,方便了更大规模的软件开发 模板是以一种完全通用的方法来设计函数或类而不必预先说明将被使用的每 个对象的类型。通过模板可以产生类或函数的集合,使它们操作不同的数据 类型,从而避免需要为每一种数据类型产生一个单独的类或函数。 例如:设计一个求两参数最大值的函数,不使用模板时,需 要定义四个函数 int max (int a, int breturn(a>b)?a, b; 1 long max (long a, long breturn(a>b)?a, b j double max(double a, double breturn(a>b)? a, b 3 char max(char a, char breturn(a>b)?a, b; 5 若使用模板,则只定义一个函数: Templateb)a, b; 1
所谓模板是一种使用无类型参数来产生一系列函数或类的机制,是C++的一 个重要特性。它的实现,方便了更大规模的软件开发。 ◼模板是以一种完全通用的方法来设计函数或类而不必预先说明将被使用的每 个对象的类型。通过模板可以产生类或函数的集合,使它们操作不同的数据 类型,从而避免需要为每一种数据类型产生一个单独的类或函数。 例如:设计一个求两参数最大值的函数,不使用模板时,需 要定义四个函数: int max(int a,int b){return(a>b)?a,b;} long max(long a,long b){return(a>b)?a,b;} double max(double a,double b){return(a>b)?a,b;} char max(char a,char b){return(a>b)?a,b;} 若使用模板,则只定义一个函数: Template type max(type a,type b) {return(a>b)?a,b;}
C艹+程序由类和函数组成,模板也分为类模板( class template) 和函数模板( function template)。 191函数模板 利用函数模板,可以建立一个具有通用功能的函数,支持不 同的函数参数和返回值,达到减少代码书写量的目的。 1、函数模板的一般说明形式如下: template (模板函数形参表) //函数定义体 其中,可以包含基本数据类型,也可以包含类类 型。类型形参需要加前缀 class。如果类型形参多于一个,则 每个类型形参都要使用 class中的参数必 须是惟一的,而且在中至少出现一次
利用函数模板,可以建立一个具有通用功能的函数,支持不 同的函数参数和返回值,达到减少代码书写量的目的。 【 19.1 函数模板】 C++程序由类和函数组成,模板也分为类模板(class template) 和函数模板(function template)。 1、函数模板的一般说明形式如下: template (模板函数形参表) { //函数定义体 } 其中,可以包含基本数据类型,也可以包含类类 型。类型形参需要加前缀class。如果类型形参多于一个,则 每个类型形参都要使用class。中的参数必 须是惟一的,而且在中至少出现一次
2、使用函数模板 函数模板只是说明,不能直接执行,需要实例化 为模板函数后才能执行。 当编译系统发现有一个函数调用 () 时,将根据中的类型生成一个重载函数 即模板函数。该模板函数的定义体与函数模板 的函数定义体相同,而的类型则以的实际类型为依据
函数模板只是说明,不能直接执行,需要实例化 为模板函数后才能执行。 当编译系统发现有一个函数调用: (); 时,将根据中的类型生成一个重载函数 即模板函数。该模板函数的定义体与函数模板 的函数定义体相同,而的类型则以的实际类型为依据。 2 、 使用函数模板
例如重载函数,求绝对值的函数只要声明一个函数模板: template 0? value-value 在主程序中可以这样使用函数模板: void maino int n value=-1n Result 第一次使用函数模板abs()时 double dblvalue=1.2, diRest参为整数,由此可以推导出函数 rEsult=abs(n value 模板中的参数类型为整数,函 dblresult= abs(dblvalue;的返回(是b)时实参 cout< <n val<"m<< Results<end为双精度型,由此推导 cout< dblvalue<</"< cdblresult<<数模板中的参数类 返回值为双精度型。 121.2
template T abs(T value) { return value>0? value: -value; } 例如重载函数,求绝对值的函数只要声明一个函数模板: void main() { int nValue=-1,nResult; double dblValue=-1.2,dblResult; nResult=abs(nValue); dblResult=abs(dblValue); cout<<nValue<<″ ″<<nResult<<endl; cout<<dblValue<<″ ″<<dblResult<<endl; } -1 1 -1.2 1.2 第一次使用函数模板abs()时, 实参为整数,由此可以推导出函数 模板中的参数类型T为整数,函数 的返回值也是整数。 第二次调用abs()时实参 为双精度型,由此推导 出函数模板中的参数类 型T为双精度型,函数的 返回值为双精度型。 在主程序中可以这样使用函数模板:
例:编写一个对具有n个元素的数组a[求最小值的程序,要求 将求最小值的函数设计成函数模板。 #include void main( template class T inta[]={1,3,0,2,7,6,4,5,2} T min(t al, int n) double b[]={1.2,-3.4,6.8,9.8} coutalil minv=alil return minv 此程序的运行结果为: a数组的最小值为:0 b数组的最小值为:-3.4
例:编写一个对具有n个元素的数组a[ ]求最小值的程序,要求 将求最小值的函数设计成函数模板。 #include template T min(T a[],int n) { int i; T minv=a[0]; for(i=1;ia[i]) minv=a[i]; return minv; } void main() { int a[]={1,3,0,2,7,6,4,5,2}; double b[]={1.2,-3.4,6.8,9.8}; cout<<”a数组的最小值为:” <<min(a,9)<< endl; cout<<”b数组的最小值为:” <<min(b,4)<<endl; } 此程序的运行结果为: a数组的最小值为:0 b数组的最小值为:-3.4
注场函数定义也是函数定义的一种,必须符合C十函数的 次定义规则。例: template void swap(T& a, T& b)i Tt=aa=bb=ti int fn([ int ix=6, iy=7, ia=3, ib=5i swap(ix,iy);/产生函数定义体 swap(ia,ib);//不产生函数定义体 swap(ia,ib)的函数调用时,由于系统中已经存在int型的 swap模板函数的定义,所以就不再生成swap的模板 函数的定义了
template void swap(T& a, T& b){ T t=a; a=b; b=t; } int fn(){ int ix=6, iy=7, ia=3, ib=5; swap(ix, iy); //产生函数定义体 swap(ia, ib); //不产生函数定义体 //... } 模板函数定义也是函数定义的一种,必须符合C++函数的 一次定义规则。例: swap(ia,ib)的函数调用时,由于系统中已经存在int型的 swap模板函数的定义,所以就不再生成swap的模板 函数的定义了。 注
#include template void swap(T& a, T& b) Tt=a: a=b: b=t void main() int ix=6, iy=7,ia=303,ib=505 i double dx=3. 5, dy=5.0 char *sl=good,*s2=better/i cout<<int ix=<<ix<<,iy=<<iy<<endli cout< double dx="<<dx<<,,, dy=l<<dy<<endli cout<< char sl=l<<sl<<,, s2<<s2<<endli swap(ix ,iy)i swap(dx, dy)i swap(ia, dy)i swap(s1, $2); cout<< after swap: \n" cout<<int ix=l<<ix<<m,iy=<<iy<<endli cout<< double dx=/<<dx<<, dya<<dy<<endl cout<<“ char *sI=”<<s1<<“,s2”<<s2<<ndl
#include template void swap(T& a, T& b) { T t=a; a=b; b=t; } void main() { int ix=6,iy=7,ia=303,ib=505; double dx=3.5,dy=5.0; char *s1=“good”,*s2=“better”; cout<<“int ix=”<<ix<<“,iy=”<<iy<<endl; cout<<“double dx=”<<dx<<“,dy=”<<dy<<endl; cout<<“char * s1=”<<s1<<“,s2”<<s2<<endl; swap(ix,iy); swap(dx,dy); swap(ia,dy); swap(s1,s2); cout<<“after swap:\n”; cout<<“int ix=”<<ix<<“,iy=”<<iy<<endl; cout<<“double dx=”<<dx<<“,dy=”<<dy<<endl; cout<<“char * s1=”<<s1<<“,s2”<<s2<<endl; }
(20.2函数模板参数 模板函数调用是寻求函数模板的类型参数匹配,类型实 参和类型形参的匹配规则与函数的数据实参类型与数据 形参类型匹配的规则不同。类型实参和类型形参的匹配 规则更为苛刻 template<c1ass四 add(ia,db)函数的调用 ⅴ oid swap(T&a,T&b) 是普通的函数调用虽然 T七≡a;a=b;b=t; ia的类型和 double型不 同,但通过数据的int型 int add (double a, double b)[ 隐式转换到 double型 return atb: sWap(ia,db)函数调用, int fnot 由于ia和db的类型分别 int ia=3 为int和doub1e型,不能 double db=5.0 char sl[]=good", s2[better 统在同企理 in七 add (ia db) l/ok 南着型裔类 swap(ia, ab) //error 荐鼓藓孑递5]和 swap(sl, s2) 11 error char[7,是不同类型的
模板函数调用是寻求函数模板的类型参数匹配,类型实 参和类型形参的匹配规则与函数的数据实参类型与数据 形参类型匹配的规则不同。类型实参和类型形参的匹配 规则更为苛刻 template void swap(T& a, T& b){ T t=a; a=b; b=t; } int add(double a, double b){ return a+b; } int fn(){ int ia=3; double db=5.0; char s1[]="good", s2[]="better"; int x = add(ia, db); // ok swap(ia, db); // error swap(s1, s2); // error } add(ia,db)函数的调用 是普通的函数调用虽然 ia的类型和double型不 同,但通过数据的int型 隐式转换到double型 swap(ia,db)函数调用, 由于ia和db的类型分别 为int和double型,不能 统一在同一个类型名上, 去模板类型参数没有隐 式转换之说。 swap(s1,s2)函数调用, 由于s1和s2的类型为字 符数组char[5]和 char[7],是不同类型的 【 20.2 函数模板参数 】
1、函数的数据形参( Data Arguments) 数据形参分: 引用型参数(提倡用本项:传址 非引用型参数:传值 引用型参数分: 引用型参数:数据形参的改变会波及到数据实参的改变 常量引用型参数:在引用型参数前面加上 const,其数据形参 的改变会不允许波及到数据实参的改变
数据形参分: 引用型参数(提倡用本项):传址 非引用型参数:传值 引用型参数分: 引用型参数:数据形参的改变会波及到数据实参的改变 常量引用型参数:在引用型参数前面加上const,其数据形参 的改变会不允许波及到数据实参的改变 1、 函数的数据形参 ( Data Arguments )