C++模板提纲1.概论2.模板机制的介绍模板引子1.假如设计一个求两参数最大值的函数,在实践中我们可能需要定义四个函数:intmax(inta,intb){return(ab)?a,b;}longmax(longa,longb){return(ab)?a,b;}doublemax(doublea,doubleb){return(ab)?a,b;}charmax(chara,charb){return(ab)?a,b;}2.这些函数几乎相同,唯一的区别就是形参类型不同。3.需要事先知道有哪些类型会使用这些函数,对于未知类型这些函数不起作用。模板的概念1.所谓模板是一种使用无类型参数来产生一系列函数或类的机制。2.若一个程序的功能是对某种特定的数据类型进行处理,则可以将所处理的数据类型说明为参数,以便在其他数据类型的情况下使用,这就是模板的由来。3.模板是以一种完全通用的方法来设计函数或类而不必预先说明将被使用的每个对象的类型。4.通过模板可以产生类或函数的集合,使它们操作不同的数据类型,从而避免需要为每一种数据类型产生一个单独的类或函数。模板分类模板分为函数模板(模子)和类模板(模子),允许用户分别用它们构造(套印)出(模板)函数和(模板)类。图显示了模板(函数模板和类模板),模板函数,模板类和对象之间的关系。5模板(函数模板和类模板)模板函数模板类对象实例化实例化实例化模子求最大值模板函数实现1.求两个数最大值,使用模板templateclassTTmax(Ta,Tb){return(ab)?a,b;}2.函数模板的声明格式如下:template模板形参表返回值类型函数名(模板函数形参表){//函数定义体}其中T为类型参数,它可用基本类型或用户自定义的类型。6模板工作方式函数模板只是说明,不能直接执行,需要实例化为模板函数后才能执行在说明了一个函数模板后,当编译系统发现有一个对应的函数调用时,将根据实参中的类型来确认是否匹配函数模板中对应的形参,然后生成一个重载函数。该重载函数的定义体与函数模板的函数定义体相同,它称之为模板函数7#includeiostream.htemplateclassTTmin(Ta[],intn){inti;Tminv=a[0];for(i=1;in;i++){if(minva[i])minv=a[i];}returnminv;}编写一个对具有n个元素的数组a[]求最小值的程序,要求将求最小值的函数设计成函数模板。voidmain(){inta[]={1,3,0,2,7,6,4,5,2};doubleb[]={1.2,-3.4,6.8,9,8};cout“a数组的最小值为:”min(a,9)endl;cout“b数组的最小值为:”min(b,4)endl;}此程序的运行结果为:a数组的最小值为:0b数组的最小值为:-3.4在函数模板中允许使用多个类型参数。但在template定义部分的每个模板形参前必须有关键字class。#includeiostream.htemplateclasstype1,classtype2voidmyfunc(type1x,type2y){coutx““yend1;}voidmain(){myfunc(10,”hao”);myfunc(0.123,10L);}程序运行结果为:10hao0.12310在template语句与函数模板定义语句之间不允许有别的语句。//这是不能编译的TemplateclassTinti;//错误,不允许有别的语句Tmax(Tx,Ty){return(xy)?x:y;}模板函数类似于重载函数,只不过它更严格一些而已。函数被重载的时候,在每个函数体内可以执行不同的动作,但同一函数模板实例化后的所有模板函数都必须执行相同的动作。//不能做函数模板的voidoutdate(inti){couti;}voidoutdata(doubled){cout”d=”dendl;}8模板优缺点函数模板方法克服了C语言解决上述问题时用大量不同函数名表示相似功能的坏习惯克服了宏定义不能进行参数类型检查的弊端克服了C++函数重载用相同函数名字重写几个函数的繁琐缺点,调试比较困难一般先写一个特殊版本的函数运行正确后,改成模板函数11类模板和模板类一个类模板(也称为类属类或类生成类)允许用户为类定义一种模子,使得实例化类中的某些数据成员,某些成员函数的参数或者返回值,能取任意数据类型。定义一个类模板,其格式如下:templateclassTypeclass类名{//…};关键字class(或typename)后面的Type是类型参数。在实例化类定义中,欲采用通用数据类型的数据成员,成员函数的参数或返回值,前面需要加上Type。例:下面的程序中建立了一个用来实现堆栈的类模板。constintsize=10TemplateclassTypeclassstack{Typestck[size];inttop;public:voidinit(){top=0;}voidpush(Typech);Typepop();};•成员函数push()和pop()在类定义体外定义,如果该成员函数中有模板参数,则需先进行模板声明,再用类模板名来限定函数名,即在函数名前,类名后缀上“Type”templateclassTypevoidstackType::push(Typeob){if(top==size){cout”stackisfull”;return;}stck[top]=ob;top++;}templateclassTypeTypestackType::pop(){if(top==0){cout”stackisempty”;return0;}tos--;returnstck[top];}类模板不代表一个具体的、实际的类,而代表一类类。实际上,类模板的使用就是将类模板实例化成一个具体的类,它的格式为:类名实际的类型对象名;例如,使用上面的类模板,创建两个模板参数为char型的对象,语句如下:stackchars1,s2;类模板stack(Type)模板类stack(char)模板类stack(int)模板类stack(double)实例化实例化实例化例类模板stack的例子,在此建立了字符型和整型两个堆栈。#includeiostream.hconstintsize=10;templateclassType//声明一个类模板classstack{//定义类模板Typestck[size];//数组可取任意类型,即模板参数类型TypeInttop;public:voidinit(){top=0;}voidpush(Typech);//参数取Type类型Typepop();//返回类型取Type类型};templateclassTypevoidstackType::push(Typeob){if(top==size){cout”stackisfull”;return;}stck[top]=ob;top++;}templateclassTypeTypestackType::pop(){if(top==0){cout”stackisempty”;return0;}top--;returnstck[top];}voidmain(){//定义字符堆栈stackchars1,s2;inti;s1.init();s2.init();s1.push(‘a’);s2.push(‘x’);s1.push(‘b’);s2.push(‘y’);s1.push(‘c’);s2.push(‘z’);for(i=0;i3;i++)cout”pops1:”s1.pop()endl;for(i=0;i3;i++)cout”pops2:”s2.pop()endl;//定义整型堆栈stackintis1,is2;//创建两个模板参数为int型的对象is1.init();is2.init();is1.push(1);is2.push(2);is1.push(3);is2.push(4);is1.push(5);is2.push(6);for(i=0;i3;i++)cout”popis1:”is1.pop()endl;for(i=0;i3;i++)cout”popis2:”is2.pop()endl;}程序运行结果如下:pops1:cpops2:zpopis1:5popis2:6pops1:bpops2:ypopis1:3popis2:4pops1:apops2:xpopis1:1popis2:2说明:(1)在每个类模板定义之前,都需要在前面加上模板声明templateclassType类模板在使用时,必须在名字后面缀上模板参数TypestackType(2)模板类可以有多个模板参数,在下面的例中建立了使用两个模板参数的类模板。例使用两个模板参数的类模板#includeiostream.htemplateclassT1,classT2//声明具有两个参数的模板classmyclass{//定义类模板T1i;T2j;public:myclass(T1a,T2b){i=a;j=b;}voidshow(){cout”I=”i”j=”jendl;}};voidmain(){myclassint,doubleod1(12,0.15);myclasschar,char*ob2(‘x’,”Thisisatest”);od1.show();ob2.show();}程序运行结果如下:I=12j=0.15I=xj=Thisisatest