模板的引入程序设计中,当参与运算的数的值会随实际情况而变化时,就使用变量来代替这个数。同理,当处理的数据类型随实际情况变化时,可以将数据类型作为可变的部分(类型参数),从程序中抽取出来。当出现真实的数据类型时,再用具体的数据类型代替;模板就是为解决这个问题而产生C++中对数据进行处理的主体可以是函数,也可以是类,因此模板包括函数模板、类模板。模板在C++标准库中,几乎所有的代码都是模板代码。模板是一种参数化的多态工具。所谓参数化的多态性,是指将程序所处理的对象的类型参数化,使一段程序代码可以用于处理多不同类型的对象。采用模板编程,可以为各种逻辑功能相同而数据类型不同的程序提供一种代码共享的机制。继承和组合提供了重用对象代码的方法,而模板提供了重用源代码的方法。问题考虑求两数中大值函数max(a,b)对于a,b的不同类型,都有相同的处理形式:returnab?a:b;用已有方法解决:(1)宏替换#definemax(a,b)((a)(b)?(a):(b))问题避开类型检查(2)重载问题需要许多重载版本(3)使用函数模板模板分类函数模板(functiontemplate)类模板(classtemplate)函数模板对不同类型的数据执行相似的操作–函数重载–函数模板函数重载——代码冗余–增加编程负担–程序的维护问题(如功能修改)函数模板C++提供的函数模板可以定义一个对任何类型变量进行操作的函数函数模板为所有的函数提供唯一的一段函数代码,增强了函数设计的通用性使用函数模板的方法是先说明函数模板,然后实例化成相应的模板函数进行调用执行–函数模板不是函数,不能被执行–置换代码中的类型参数得到模板函数——实例化–实例化后的模板函数是真正的函数,可以被执行函数模板模板函数实例化函数模板的定义函数模板的一般说明形式如下:template模板形参表返回值类型函数名(模板函数形参表){//函数定义体}函数模板的定义以关键字template开头template之后中是函数模板的参数列表函数模板的参数是类型参数,其类型为class或typename–templateclassT–templateclassT1,classT2函数模板的定义模板的参数定义之后是函数模板的定义,是一个将类型参数作为某种类型使用的函数函数模板的参数名在模板中作为一种类型使用,可以用于函数的形参、函数返回值和函数的局部变量模板的每个形式参数要在函数的参数列表中至少出现一次形式参数名的作用域局限于函数模板的范围内函数模板的定义示例#includeiostream.h#defineSIZE8templateclassElementTypevoidsortArray(ElementTypeb[],intlen){for(intpass=0;passlen-1;pass++)for(inti=pass+1;ilen;i++)if(b[pass]b[i]){ElementTypehold;hold=b[pass];b[pass]=b[i];b[i]=hold;}}templateclassElementTypevoiddisplayArray(ElementTypeb[],intlen){for(intindex=0;index=len-1;index++)if(index!=len-1)coutb[index]\t;elsecoutb[index]endl;}函数模板的使用函数模板规定了对数据的处理流程某些数据类型(模板的参数)要等到模板实例化时再确定具体的类型函数模板的实例化由编译器来完成–根据函数调用的实参类型确定模板形参的具体类型–用相应的类型替换函数模板中的模板参数完成函数模板的实例化函数模板的使用示例voidmain(){intai[SIZE]={18,35,36,61,9,112,77,12};doubleaf[SIZE]={12.1,-23.8,3.7,-16.0,9.1,12.12,7.7,56.3};coutBeforesorting:\nai:\t;displayArray(ai,SIZE);sortArray(ai,SIZE);coutAftersorting:\nai:\t;displayArray(ai,SIZE);cout“Beforesorting:\n”af:\t;displayArray(af,SIZE);sortArray(af,SIZE);coutAftersorting:\naf:\t;displayArray(af,SIZE);}重载函数模板C++语言允许一个函数模板可以使用多个模板参数或者重载一个函数模板用户可以用非模板函数重载一个同名的函数模板类模板类模板:将类定义中的数据类型参数化类模板实际上是函数模板的推广,可以用相同的类模板来组建任何类型的对象集合类模板的定义template类型形参表class类名{//类说明体};template类型形参表返回类型类名类型名表::成员函数1(形参表){//成员函数定义体}template类型形参表返回类型类名类型名表::成员函数2(形参表){//成员函数定义体}…template类型形参表返回类型类名类型名表::成员函数n(形参表){//成员函数定义体}类模板的定义示例//tstack.h:类模板的定义templateclassElementTypeclassStack{public:Stack(int=8);//省缺栈元素的树数目为8~Stack(){delete[]data;};intpop(ElementType&num);intpush(ElementTypenum);private:ElementType*data;//栈数据存储intmemNum;//栈元素个数intsize;//栈大小};类模板的定义示例//stack.cpp:类模板的实现templateclassElementTypeStackElementType::Stack(ints){size=s0?s:8;data=newElementType[size];memNum=0;}templateclassElementTypeintStackElementType::pop(ElementType&num){if(memNum==0)return0;num=data[--memNum];return1;}templateclassElementTypeintStackElementType::push(ElementTypemem){if(memNum==size)return0;data[memNum++]=mem;return1;}使用类模板类模板的实例化:用具体的数据类型替换模板的参数以得到具体的类(模板类)模板类也可以实例化为对象用下列方式创建类模板的实例:类名类型实参表对象名称;实例化实例化类模板模板类对象类模板的使用示例#includeiostream.h#includetstack.hintmain(){StackdoubledoubleStack(6);doublef=3.14;coutPushingelementsintodoubleStack:\n;while(doubleStack.push(f)){coutf'';f+=f;}cout\nStackisfull.CannotpushfontothedoubleStack.;cout\nPoppingelementsfromdoubleStack:\n;while(doubleStack.pop(f))coutf'';类模板的使用示例cout\nStackisempty.Cannotpop.\n;StackintintStack;inti=1;cout\nPushingelementsintointStack:\n;while(intStack.push(i)){couti'';++i;}cout\nStackisfull.pushifailed.;cout\n\nPoppingelementsfromintStack:\n;while(intStack.pop(i))couti'';cout\nStackisempty.Cannotpop.\n;return0;}派生类模板通过继承可以产生派生类通过继承同样可产生派生的类模板几种不同的派生:–从一般类派生出类模板–从类模板中派生出类模板从一般类派生出类模板一般类(其中不使用类型参数的类)作基类,派生出类模板(其中要使用类型参数)基本语法:classCB{//CB为一般类...};templateclassTclassCA:publicCB{//被派生出的CA为类模板,使用了类型参数TTt;//私有数据为T类型的public:...};从类模板派生出类模板类模板作基类,派生出新的类模板。但仅基类中用到类型参数T(而派生的类模板中不使用T)基本语法:templateclassTclassCB{//CB为类模板Tt;//私有数据为T类型的public:Tgett(){//用到类型参数Treturnt;}...};templateclassTclassCA:publicCBT{//CA为类模板,其基类CB为类模板//将被“传递”给基类CB,本派生类中并不使用该类型参数Tdoublet1;//私有数据成员...};从类模板派生出类模板类模板作基类,派生出新的类模板,且基类与派生类中均使用同一个类型参数TtemplateclassTclassCB{//CB为类模板(其中使用了类型参数T),它将作为类模板CA的基类Tt;//数据成员为T类型的public:Tgett(){//用到类型参数Treturnt;}...};templateclassTclassCA:publicCBT{//CA为类模板,其基类CB也为类模板。注意,类型参数T将被“传递”给基类CB;本派生类中也将使用这同一个类型参数TTt1;//数据为T类型的public:...};从类模板派生出类模板类模板作基类,派生出新的类模板,但基类中使用类型参数T2,而派生类中使用另一个类型参数T1(而不使用T2)templateclassT2classCB{//CB为类模板(其中使用了类型参数T2),它将作为类模板CA的基类T2t2;//数据为T2类型的public:...};templateclassT1,classT2classCA:publicCBT2{//CA为类模板,其基类CB也为类模板。注意,类型参数T2将被“传递”给基类CB;本派生类中还将使用另一个类型参数T1T1t1;//数据为T1类型的public:...};类模板继承示例#ifndefCMYSTRING_H#defineCMYSTRING_H#pragmawarning(disable:4786)#includestringusingnamespacestd;classCMyString:publicbasic_stringchar{public:voidTrim();voidLTrim();voidRTrim();CMyString();CMyString(constchar*s);};#endif类模板继承示例#includeCMyString.hvoidCMyString::LTrim(){string::size_typelen;if((len=this-size())==0){return;}this-erase(0,this-find_fir