《C++面向对象程序设计》第9章 模板_第1页
《C++面向对象程序设计》第9章 模板_第2页
《C++面向对象程序设计》第9章 模板_第3页
《C++面向对象程序设计》第9章 模板_第4页
《C++面向对象程序设计》第9章 模板_第5页
已阅读5页,还剩35页未读 继续免费阅读

下载本文档

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

文档简介

《C++面向对象程序设计》教学内容

第1章C++概述

第2章类和对象

第3章面向对象程序设计概述

第4章进一步学习类和对象

第5章堆与复制构造函数

第6章继承性:派生类

第7章运算符重载

第8章虚函数和多态性

第9章模板

第10章类库和C++的标准模板库STL

第11章输入输出流

第12章异常处理

第9章模板

9.1模板的概念

9.2函数模板

9.3重载模板函数

9.4类模板的定义

9.5使用类模板

9.6应用举例

问题的引入

•很多算法本身的描述其实与其所涉及数据的类型

是无关的。

•但是,高级语言大多数都是基于类型系统的语言,

当用高级语言表达算法的实现时,就必须明确指

出其具体的数据类型,

•这样以来就必然导致同一个算法有多个不同的实

现(针对不同的数据类型)。

•从而使工作量加大,使用麻烦,维护困难。

例:将两个数进行交换(请同学们想一想共

有几种方案?)

解决方案一:宏定义

•在C语言中,宏定义是解决类型无关算

法的首选解决方案。例:

#definemax(x,y)((x)>(y)?(x):(y));

•宏定义有如下的缺点:

重复计算

只能处理简单的情况

例如:这里的Swap(x,y)使用宏定义就不好处理。

解决方案二:用C语言的函数

voidSwapl(int*x,int*y)

inttemp;

temp=*x;

*x=*y;

*y=temp;

}

voidSwapF(float*x,float*y)从上面的实现可以看

(出,这种方案不仅实

floattemp;现上浪费很大,而且

temp=*x;使用起来非常的不方

*x=*y;便(不同的函数名)。

*y=temp;

解决方案三:C++函数名重载

voidSwap(int&x,int&y)

(

inttemp;

temp=x;

x=y;

y=temp;

}

voidSwap(float&x,float&y)与C语言相比,C++

{的函数名重载让使用者

floattemp;

temp=x;大大地得到了解放,但

x=y;实现者还是需进行大量

y=temp;

的重复性劳动。

解决方案四:模板

template<classT>

voidswap(T&x5T&y)

{Tt;xy-所--谓---模--板--是---一--种---是--将--类----、

t=X;|型参数化来产生一系列

Y函数或类的机制。

y=t;

9.1模板的概念

•模板的英文为template,又可译作样板。

•C++中的模板可以用来设计与数据类型无

关的通用算法。

■这样的通用算法能够适用不同场合下不

同的数据类型。

•通过针对不同的数据类型实例化这些模

板,可以实现代码重用,从而达到提高

软件生产率的目的。

模板的作用

•通过模板可以产生类或函数的集合,使

它们操作不同的数据类型,

•从而避免需要为每一种数据类型都编写

一个单独的类或函数。

什么是模板template?

9.2函数模板

template<classtype>ret_type

func_name(parameterlist)

{//bodyoffunction}

•type是函数模板所使用的数据类型的占

位符名称,又称为模板参数。

•将type实例化的类型称为模板实参,用

模板实参实例化函数模板得到的函数称

为模板函数。

函数模板的两种实例化方式

〃显式实例化

〃隐式实例化

#include<iostream>

usingnamespacestd;

template<classT>Tmin(Ta,Tb)

return(a<b)?a:b;

函数模板的两种实例化方式(续)

intmain()

使用整型类型int

显式实例化。

doubledobjl=l.l,dobj2=2.2;j

charcobjl-c\cobj2='W;

inti=12,j=68;

使用double隐式

cout«min<int>(i,cobj1)«endl;实例化

cout«min(dobj1,dobj2)«endl;

cout«min<char>(cobj2,j)«endl;

return0;

使用字符类型,

char显式实例化

实例:求绝对值的函数模板

#include<iostream>

usingnamespacestd;

template<classX>Xmyabs(Xval)

{

returnval<0?-val:val;

)

intmain()

{

cout«myabs(-lO)«'\n';//integerabs

cout«myabs(-lO.O)<<'\n';//doubleabs

cout«myabs(-lOL)«'\n';//longabs

cout«myabs(-lO.OF)«'\n';//floatabs

return0;

函数模板与函数重载

•在每个重载函数的函数体中,可以执行不同的

行为。

•但是,函数模板的所有实例都必须执行同样的

行为——只有数据类型可以不同。

voidoutdata(inti)

{]这些函数不能.

cout«i;用函数模板来

}实现

voidoutdata(doubled)

cout«d*3.1416;

定义多个重载函数使代码显得冗长

//对于整数类型

intmax(inta,intb){return(a>b)?a,b;}

//对于长整数类型

longmax(longa,longb){return(a>b)?a,b;}

//对于单精度浮点数

floatmax(floata,floatb){return(a>b)?a,b;}

//对于双精度浮点数

doublemax(doublea,doubleb)

{return(a>b)?a,b;}

模板函数的代码更加简洁

•如果使用函数模板就可以减少这些不必要的

重复。例如:

template<classtype>typemax(typea,typeb)

{return(a>b)?a,b;}

•可见,模板可以大大提高程序代码的灵活

性,减少源代码长度。从而减轻程序员的负

相。

注意

函数模板实例化时不支持数据类型的自动转换

当用隐式方式时,下面的方式将是一种错误:

swap(i,c);

因为i和cl的类型不一致,无法实例化函数模

板swap(T&x,T&y)o

但是,当用显式方式将其声明为:

voidswap(int&,int&)后,则可以合法去调用

了。

函数模板小结

•无论操作的是什么类型的数据,许多

算法在逻辑上是相同的。

•通过建立函数模板,可以不依赖于任

何数据类型来描述算法。

・函数模板定义了一套适用于各种数据

类型数据的一般操作。

•函数模板是描述通用算法的强有力的

手段。

9.3重载函数模板

//max.h

template<classTYPE>

TYPEmax(TYPEa,TYPEb)

(

return(a>b?a:b);

)

template<classTYPE>

TYPEmax(TYPEa,TYPEb,TYPEc)

(

TYPEt;

t=(a>b)?a:b;

return(t>c)?t:c;

}

注:这种重载是指参数个数不同,而不是类型不同。

实例化函数模板时自动匹配

#include“iostream.h"

#include"max.h"

intmain()

{char*maxi;

intx=10,y=20,max2;

doublea=10.3,b=21.7,c=14.5,max3;

max2=max(x,y);

max3=max(a,b,c);

maxl=max(nX¥Zn,nABCn);

cout«nThemaximumofn«x

«nandn«y«nis:n«max2«endl;

cout«nThemaximumofn«a«M,M

«b«nandn«c«nis:n«max3«endl;

cout«nThemaximumof\nXYZ\nand\nABC\nis:n«maxl«endl;

return0;

输出结果分析

•其结果是:

Themaximumof10and20is:20

Themaximumof10.3,21.7and14.5is:21.7

ThemaximumofnXYZnand“ABCnis:ABC

为什么会出错?如

何改正这个错误?

出错的原因

•当用char*实例化函数模板max时,得到

的模板函数如下:

char*max(char*a,char*b)

(

return(a>b)?a:b;

)

它所比较的是两个字符串存储单元地址的大小,

而不是两个字符串的内容。

改正错误的方法

•只要用一个普通的函数进行重载就可以

了,比如:

char*max(char*a5char*b)

return(strcmp(a5b)>0?a:b);

一般的函数重载函数模板

•即用一个非函数模板重载一个同名的函

数模板。

•目的是用一般函数来完善或者弥补模板

函数所描述的问题的漏洞。

•例:用char*实例化上例就会出现问题。

下面两个声明将指同一个函数模板

Template<classTl>

T1max(Tla,Tlb)

{

return(a>b)?a:b;

Template<classT2>

T2max(T2a,T2b)

return(a>b)?a:b;

二义性错误

因为T1和T并不指某个具体的类型,当用:

intmax(int,int);

时,编译器将不知道用那一个模板将其实例

化,从而产生二义性错误。

重载函数的调用次序

•寻找一个参数完全匹配的函数,若找到就

调用之。

•否则,寻找一个函数模板,将其实例化产

生一个匹配的函数,若有则调用之。

•否则,在重载函数中找有无通过类型转换

可产生参数匹配的函数,若有则调用之。

•若通过以上三步均没找到,则出现无匹配

函数的错误。若在某一步上同时有多于一

个的选择,则为二义性错误。

9.4类模板的定义

问题引入:

与函数模板相似,我们在设计类时也往

往会遇到由于数据类型的不同而不得不

重复地进行类的设计,而这些类的形式

是十分相象的,基于象引入函数模板同

样的原因,C++引入了类模板机制。

例:栈类模板

通用栈解决方案一:继承

整数栈浮点数栈用户定义类型的栈

通用栈解决方案二:模板

constintSIZE=10;

template<classT>classstack{

Tstck[SIZE];//使用数组实现堆栈

inttos;//top-of-stack堆栈顶部位置

public:

stack();//constructor

voidpush(Tch);〃将数据压入堆栈

Tpop();〃从堆栈弹出数据

);

类模板定义的一般形式

template<class模板形参表〉

class类模板名

〃类体

);

成员函数在类模板的体外实现

如果成员函数在类模板的体外实现,则每

个成员函数前都必须用与声明该类模板

一样的方法声明:

template<class模板形参表,

使这样的成员函数成为一个函数模板。

成员函数在类模板的体外实现实例

template<classT>voidstack::push(Td)

(

if(tos=SIZE){

cout«nStackisfull\nn;

return;

}

stck[tos]=d;

tos++;

)

template<classT>Tstack::pop()

(

if(tos==0){

cout«HStackisempty\nn;

return0;//returnnullonemptystack

}

tos—;

returnstckftos];

9.5使用类模板

•类模板必须显式实例化为模板类后才能使用,

如:

stack<int>

就产生一个整形的模板类。

­类模板必须显式实例化后,才能生成对象:

模板名V类型实参表,对象名(值实参表);

stack<int>int_stack;

安全数组模板类实例

constintSIZE=10;

template<classAType>classatype{

ATypea[SIZE];

public:

atype(){

registerinti;

for(i=0;i<SIZE;i++)a[i]=i;

)

ATyp

温馨提示

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

评论

0/150

提交评论