面向对象程序设计辅导材料-1_第1页
面向对象程序设计辅导材料-1_第2页
面向对象程序设计辅导材料-1_第3页
面向对象程序设计辅导材料-1_第4页
面向对象程序设计辅导材料-1_第5页
已阅读5页,还剩44页未读 继续免费阅读

下载本文档

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

文档简介

第12章模板(Template)面向对象程序设计(C++)12.1引言12.1引言:IntStack创建一个栈,这个栈类只存放int类型的值1.支持初始化、push()、pop()、清除等方法;2.栈中所有元素的类型都是int.VP用来存放int的栈类IntStackclassIntStack{int*v;//栈底int*p;//栈顶intsz;//栈的大小public:IntStack(ints){v=p=newint[sz=s];}~IntStack(){delete[]v;}voidpush(inta){*p++=a};intpop(){return*--p;}intsize()const{returnp-v;}};12.2代码重用12.2如何实现代码重用?VPVPCharStackObjStack

现在希望再创建能存放其他类型的栈类,如:char,float,甚至用户自定义的类型对象。

从栈的结构和操作方式上来说,除了每个元素的类型不一样外,其它没有任何区别。因此应该可以重用IntStack的代码。问题是:如何重用?12.2.1C的方法之一:代码拷贝classCharStack{

char*v;//栈底char*p;//栈顶intsz;//栈的大小public:CharStack(ints){v=p=newchar[sz=s];}~CharStack(){delete[]v;}voidpush(chara){*p++=a};

charpop(){return*--p;}intsize()const{returnp-v;}};缺点:1.表现繁琐;2.易发生错误;3.缺乏美感;非常低效!12.2.2C的方法之二:typedeftypedefintT;classStack{

T*v;//栈底

T*p;//栈顶intsz;//栈的大小public:Stack(ints){v=p=newT[sz=s];}~Stack(){delete[]v;}voidpush(Ta){*p++=a};

Tpop(){return*--p;}intsize()const{returnp-v;}};缺点:1.每次使用Stack之前,都必须加上typedef语句,很麻烦。2.由于T是全局名,无法重新定义,一个类不能同时用到char栈和int栈;12.2.3smalltak方法(略)使用继承复杂,混乱!12.2.4C++的方法:模板改进typedef,将它从预处理器移入到编译器中。新的代码替换装置称为“模板”(template)。非常象宏,却更清晰,更易于使用;模板实际上是一组类;形式上很简洁。12.3模板语法12.3.1类模板定义template<classT>class类模板名{//类模板的定义};注:T是一个类模板的类型参数,可以有一个或多个,可以是任意类型。template<classT>

classStack{

T*v;//栈底

T*p;//栈顶intsz;//栈的大小public:Stack(ints){v=p=newT[sz=s];}~Stack(){delete[]v;}voidpush(Ta){*p++=a};

Tpop(){return*--p;}intsize()const{returnp-v;}};例:Stack<T>12.3.2类模板实例化给类模板的参数指定具体的类型,这一过程称为

“类模板的实例化”。类模板名<具体类型表>

Stack<int>;//实例化成int型栈类;Stack<char>;//实例化成char型栈类;注意:类模板实例化后的结果是类,而不是对象!12.3.3类对象生成类模板实例化得到的类可以进行实例化,生成最终的对象。Stack<int>si(20);//创建一个大小为20的整形栈;Stack<char>si(40);//创建一个字符型栈;Stackstack(100);//error,未指定模板参数,

类模板与类的实例化Stack<T>Stack<int>Stack<char>…………Stack<int>sint(10)Stack<int>si2(20)……模板实例化类实例化完整的stack<T>程序:template<classT>classStack{

T*v;//栈底

T*p;//栈顶intsz;//栈的大小public:Stack(ints){v=p=newT[sz=s];}~Stack(){delete[]v;}voidpush(Ta){*p++=a};

Tpop(){return*--p;}intsize()const{returnp-v;}};voidmain(){inti;Stack<char>sch(20);

Stack<char>sch2(20);

Stack<int>sint(10);for(i=0;i<10;i++){sint.push(i+1);}for(i=0;i<20;i++){sch.push(‘*’);}//….for(i=10;i>0;i--){if(sint.pop()!=i){error();}}for(i=0;i<20;i++){if(sch.pop()!=‘*’){error();}}}一个值得注意的问题!12.3.4非内联函数定义12.3.4.1语法template<classT>返回值类型类模板名<类模板参数>::成员函数名(函数参数1,函数参数2,函数参数3)非内联函数定义的Stack<T>template<classT>classStack{T*v;//栈底T*p;//栈顶intsz;//栈的大小public:Stack(ints;~Stack();voidpush(Ta);Tpop();intsize();};template<classT>Stack<T>::Stack(ints){v=p=newT[sz=s];}template<classT>Stack<T>::~Stack(){delete[]v;}

template<classT>voidStack<T>::push(Ta){*p++=a};template<classT>TStack<T>::pop(){return*--p;}template<classT>intStack<T>::size()const{returnp-v;}};12.3.4.2关于头文件对类来说,在创建非内联函数定义时,我们通常把定义放在.h文件中,而把实现放在.cpp中。

(实际上是所谓的头文件原则:“在头文件中,不要放置分配存储空间的任何东西”,为了防止在连接期间的多重定义错误。)对模板来说,即使是在创建非内联函数定义时,模板的所有定义和实现都必须放入一个头文件中。

why?

因为模板很特殊,在template<…>之后的任何东西都意味着编译器在当时不为它分配存储空间(即不编译成目标代码),而是一直处于等待状态直到一个模板示例被告知。如果没有被实例化,模板不会被编译成目标代码:template<classT>classStack{

T*v;//栈底

T*p;//栈顶intsz;//栈的大小public:Stack(ints;~Stack();voidpush(Ta);

Tpop();intsize();};文件:Stack.htemplate<classT>Stack<T>::Stack(ints){v=p=newT[sz=s];}template<classT>Stack<T>::~Stack(){delete[]v;}template<classT>voidStack<T>::push(Ta){*p++=a};

template<classT>

TStack<T>::pop(){return*--p;}

template<classT>intStack<T>::size()const{returnp-v;}};文件:Stack.cpp#include“Stack.h”voidmain(){Stack<int>si(10);si.push(1);//连接错误}文件:test.cpperrorLNK2001:unresolvedexternalsymbol"public:int__thiscallStack<int>::push(int)"(?push@?$stack@H@@QAEHXZ)发生连接错误:FromMSDN:LinkerToolsErrorLNK2001unresolvedexternalsymbol"symbol"Codewillgeneratethiserrormessageifitreferencessomething(likeafunction,variable,orlabel)thatthelinkercan’tfindinallthelibrariesandobjectfilesitsearches.Ingeneral,therearetworeasonsthiserroroccurs:whatthecodeasksfordoesn’texist(thesymbolisspelledincorrectlyorusesthewrongcase,forexample),orthecodeasksforthewrongthing(youareusingmixedversionsofthelibraries?somefromoneversionoftheproduct,othersfromanotherversion).NumerouskindsofcodingandbuilderrorscancauseLNK2001.Severalspecificcausesarelistedbelow,andsomehavelinkstomoredetailedexplanations.……12.3.5模板中的常量模板参数并不局限于类定义的类型,可以使用编译器内置类型。

tempate<classT,intsize=100>classArray{…;}类型参数内置类型参数参数的默认值例:模板中的常量#include"../require.h"#include<iostream>usingnamespacestd;template<classT,intsize=100>classArray{Tarray[size];//在实例化时,设置Array类的长度public:T&operator[](intindex){//重载[]实现关联数组

require(index>=0&&index<size,"Indexoutofrange");returnarray[index];}intlength()const{returnsize;}};classNumber{floatf;public:Number(floatff=0.0f):f(ff){}Number&operator=(constNumber&n){//重载赋值符f=n.f;return*this;}operatorfloat()const{returnf;}

friendostream&operator<<(ostream&os,constNumber&x){returnos<<x.f;}};template<classT,intsize=20>classHolder{Array<T,size>*np;public:Holder():np(0){}T&operator[](inti){require(0<=i&&i<size);if(!np)np=newArray<T,size>;returnnp->operator[](i);}intlength()const{returnsize;}~Holder(){deletenp;}};intmain(){Holder<Number>h;

for(inti=0;i<20;i++)h[i]=i;

for(intj=0;j<20;j++)cout<<h[j]<<endl;}///:~12.4模板的派生12.4.1从类派生模板模板实际上是一组类,如果某一类定义了这一组类的公共属性,则模板可以从该类派生。classBase{inti;protected:floatf;public:voidg(){cout<<“g”<endl;}};template<classT>classderived:publicBase{Tt;//…};voidmain(){derived<int>di;derived<char>dc;di.g();//dc.g();}12.4.2从类模板派生模板template<classT>classBase{inti;protected:Tf;public:voidg(){cout<<“g”<endl;}};类模板的基类如果也是模板,派生类模板的参数表应包含基类模板的参数。template<classT1,classT2>classderived:publicBase<T2>{T1t;//…};voidmain(){derived<int,char>di;derived<char,float>dc;di.g();//dc.g();}12.4.2从类模板派生模板(续)如果派生类没有类型参数,或者说它的类型参数与基类的类型参数相同时,派生类地模板参数只要包含基类的模板参数就可以了template<classT>classC:publicBase<T>//模板C的参数与基类相同{Tc;//…};12.5函数模板实际上是定义了一组函数12.5.1函数模板的定义template<模板参数表>返回值类型函数名(函数参数表){//函数模板的定义}例1:求两个对象间的最大值template<classT>Tmax(Ta,Tb){returna>b?a:b;}这里T可以是int,char,float,或者任何重载了>算符的对象。例2:关于模板参数template<classT>voidf(){//error,函数参数列表中无函数模板参数TTa;//…}12.5.2函数模板的实例化函数模板的实例化不需要用户显式进行,而是在函数调用时由编译器来处理。voidmain(){inta,b;charc,d;intm1=max(a,b);//调用max(inta,intb);charm2=max(c,d);//调用max(charc,chard);}

温馨提示

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

评论

0/150

提交评论