版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、第五章,模 板,主要内容,模板的概念 函数模板和模板函数 类模板和模板类,5.1 模板的概念,引例: int max( int x, int y) return (xy) ? x: y; double max( double x, double y) return (xy) ? x: y; char max( char x, char y) return (xy) ? x: y; ,可以看出,这些函数版本的功能都是相同的,只是参数类型和函数返回类型不同。 那么能否为这些函数只写出一套代码呢?,C+解决这个问题的一个方法就是使用模板。,利用模板机制可以显著减少冗余信息,能大幅度地节约程序代码,进
2、一步提高面向对象程序的可重用性和可维护性 模板概念是对类属概念的继承与发展。,类属,类属是 一种参数多态的机制。 ALGOL68语言最先引入类属(genericity)的概念,最主要的类属形式是类型参数化,即用一个或多个类型去参数化一个软件元素。 基本思想: 在实际工作中人们经常用到刚才那样一些程序模块,从它们的逻辑功能(或实现算法)看,彼此是相同的,所不同的主要是处理对象(数据)的类型。 如果提供具有相同逻辑功能的程序正文(保存共性),然后把数据类型作为参数传递(指出不同特性),则可节约大量程序代码,这就是类属机制的思想,又称为参数化模板。,类属又可分为无约束类属机制和约束类属机制 无约束类
3、属机制是指对作为类属参数的数据类型没有任何特殊要求 约束类属机制则意味着对类属参数有明确要求,只有在类属实参满足一定条件时才有意义。 1. 无约束类属的例子 void swap(T ,2. 约束类属的例子 T minimum(T x,T y) if(x=y) return x; else return y; 并不是任何数据类型都可以作为这个函数的类属实参,只有满足一定条件(即定义了“=”操作)的数据类型,才能作为这个函数的类属实参。 /结构变量的比较运算与整型变量的比较运算就有很大差别 C+语言使用模板来实现类属机制。,在C+中,模板是实现代码重用机制的一种工具,它可以实现类型参数化,即把类型
4、定义为参数,从而实现代码的可重用性。 C+程序由类和函数组成,C+中的模板也分为类模板和函数模板。 例: T max( T x, T y) return (xy) ? x : y; ,1. 模板的概念,这个以参数化表示的函数称为函数模板。,所谓函数模板,实际上是建立一个通用函数,其函数类型和形参类型不具体指定,用一个虚拟的类型(如:T)来代替,这个通用函数就称为函数模板。 3. 模板函数 在定义了一个函数模板后,当编译系统发现有一个对应的函数调用时,将根据实参中的类型来确认是否匹配函数模板中对应的形参,然后生成一个重载函数,该函数的定义与函数模板的函数定义体相同,称之为模板函数。,2. 函数模
5、板,比较:函数模板和模板函数的区别,函数模板是模板的定义,定义中用到通用类型参数。 模板函数是实实在在的函数定义,它由编译系统在遇到具体函数调用时所生成,具有程序代码。,同样,类模板是模板的定义,不是一个实实在在的类,其定义也用到通用类型参数。在定义了一个类模板后,可以创建类模板的实例,即生成模板类。,4. 模板、模板函数、模板类和对象之间的关系,说明:,由于模板的作用是使程序能够对不同类型的数据进行相同方式的处理,因此,在进行相同方式的处理时,只有当参加运行的数据类型不同时,才可以定义模板。,5.2 函数模板和模板函数,函数模板的定义和模板函数的生成 1) 定义函数模板的一般形式: temp
6、late 函数返回值类型 函数名(形参表) /函数体 ,例:将求最大值的函数max()定义成函数模板。,template /模板声明 T max(T x, T y) /模板定义体 return (xy) ? x:y; 其中,T是模板形参,它既可以取系统预定义的数据类型,也可以取用户自定义的类型。,2) 模板函数的生成:,定义了函数模板后,程序中并没有得到真正的函数代码。只有用一个具体的数据类型来代替上面的类型参数T以后,即将模板具体化后,系统才会生成特定于具体数据类型的程序代码(模板函数)。,当程序中有如下语句时, int i; i=max(2, 30); 编译系统就会自动生成具有整型参数和返
7、回值的函数代码: int max( int x, int y) return (xy) ? x: y; 然后将它插入到程序中,这个生成的函数称为模板函数。这样,如果再有一句对整型参数的函数调用,系统就不会再次生成函数代码,而是直接使用已经生成的函数代码了。,例:,同样,如果程序中又有了这么一句函数调用: double x=max(12.3,48.5); 编译系统会先看有没有已经从模板生成了函数代码,如果没有,就生成具有双精度浮点型参数的函数代码: double max(double x , double y) return (xy)?x:y; ,说明:,一般来说,当编译程序看到对模板函数的调用
8、语句时,就会根据函数模板生成对应于该特定数据类型的具体函数代码。 但是,也可以通过声明函数原型来告诉编译程序实例化函数模板。例如: float max(float,float); 当编译器看到函数原型时,会先根据函数模板生成相应的函数代码。,例:见下例exec11.1。,例exec11-1 不同数据类型数组中的元素求和,#include using namespace std; template T Sum(T *array,int size=0) T total=0; for (int i=0;isize;i+) total+=arrayi; return total; int main()
9、 int int_array=1,3,5,7,9,11,13,15,17,19; double double_array=1.1,2.2,3.3,4.4,5.5,6.6,5.7,8.8,9.9,10.01; coutThe summary of integer array are Sum(int_array,10)endl; coutThe summary of double array are Sum(double_array,10)endl; return 0; ,在程序中,生成了两个模板函数: Sum(int_array,10)用实参int_array将类型参数T进行了实例化,int_a
10、rray为一整型数组名,编译程序生成一个形如int Sum(int *array,int size)的模板函数; Sum(double_array,10)用实参double_array将类型参数T进行了实例化,double_array为一双精度型数组名,编译程序生成一个形如double Sum(double *array,int size)的模板函数。,2. 函数模板的使用,虽然函数模板中的模板形参T可以实例化为各种类型,但实例化T时,虚实参之间必须保持完全一致的类型。模板类型并不具有隐式的类型转换,例如在int与char之间、float与int之间、float与double之间等的隐式类型转
11、换。 例: 见例exec11.2。,#include using namespace std; template T max(T a,T b) T c; if (ab) c=a; else c=b; return c; int main() int i1=50,i2=40; char c1=A,c2=B; double x1=45.6,x2=2.5e2; coutmax(i1,i2)endl; coutmax(c1,c2)endl; coutmax(x1,x2)endl; coutmax(i1,c1)endl; coutmax(i1,x1)endl; coutmax(c1,x1)endl; r
12、eturn 0; ,分析: 由于这3条语句的实参的类型与形参不一致,而max模板参数T的各实参之间必须保持一致的类型,因此出现编译错误。 例如,max(i1,c1) 系统找不到与max(int, char)相匹配的函数定义。,解决方法:,采用强制类型转换。 例:将调用语句max(i1, c1)改写为 max(i1, int(c1) 显式给出模板实参,强制生成对特定实例的调用。具体地说,就是在调用格式中要插入一个模板实参表。 例: cout(i1,x1)就是模板实参表,通过它通知编译系统生成对形如int max(int a, int b)的函数实例的调用。这样,在调用过程中,double型的参数
13、x1将被自动转换成int型。,例:采用上面两种方法对例exec11.2进行修改。, int main() int i1=50,i2=40; char c1=A,c2=B; double x1=45.6,x2=2.5e2; cout(i1,x1)(c1,x1)endl; /正确 return 0; ,问题: 比较两个字符串哪个大,能不能用上面的函数模板直接比较两个字符指针的大小?,分析: 比较两个字符指针的大小不能使用上述的方法(因为:s1,s2是指针),而需要用strcmp()函数来进行。因此,需要重新定义max()来比较两个字符串。 那么怎样利用函数模板来实现这一目的呢?,max(s1,s2
14、),解决方法: 允许函数模板参与重载,即允许用普通函数重载一个同名的函数模板。 有以下两种重载方式: 与函数模板共享函数体; 重新定义函数体。,与函数模板共享函数体,通过借用函数模板的函数体来定义重载函数模板的非模板函数。 例: template T max(T a,T b) T c; if (ab) c=a; else c=b; return c; int max(int, int); /与函数模板共享函数体,void f(int i,char c) int x; x=max(i,i); x=max(c,c); x= max(i,c);/调用int max(int,int); x=max(c
15、,i); /调用int max(int,int); 因为普通函数具有隐式类型转换能力,所以不出错!,重新定义函数体,在定义重载函数模板的非模板函数时,给出这个重载的非模板函数的函数体。 例: 见例exec11.4。 说明: 编译程序在处理这种情况时, 首先寻找参数完全匹配的普通函数; 然后再寻求参数完全匹配的函数模板; 最后寻求低一级的对函数的重载方法(类型转换达到匹配)。,char * max(char *a,char *b) if (strcmp(a,b)0) return a; else return b; ,函数模板总结,函数模板是对一组函数的描述,它不是一个实实在在的函数,编译系统并
16、不产生任何执行代码。 当编译系统在程序中发现有与函数模板中相匹配的函数调用时,便生成一个重载函数,该重载函数的函数体与函数模板的函数体相同。这个根据函数模板生成的重载函数称为模板函数。,函数模板与模板函数的区别如下: (1)函数模板不是一个函数,而是一组函数的模板,在定义中使用了参数类型。 (2)模板函数是一种实实在在的函数定义,它的函数体与某个函数模板的函数体相同。 编译系统遇到模板函数调用时,将生成可执行代码。 函数模板是定义重载函数的一种工具。一个函数模板只为一种原型函数生成一个模板函数,不同原型的模板函数是重载的。这样就使得一个函数只需编码一次就能用于某个范围的不同类型的对象上。 因此
17、,可以说函数模板是提供一组重载函数的样板。,5.3 类模板和模板类,使用类模板(也称为类属类或类生成类)机制,用户可以为类定义一种模式,使得类中的某些数据成员、某些成员函数的参数和某些成员函数的返回值,可以是任意类型的。 类模板不再代表一个具体的、实际的类,而是代表一类类。,1. 类模板的定义,定义类模板,包含两方面内容: 定义类; 在类定义体外定义成员函数。 1) 定义类的一般形式: template /模板声明 class Name /类的定义 ;,例1:向量类模板定义。,template class Vector T *data; int size; public: Vector(int
18、 i) data=new Ti; Vector() delete data; T ,例2:一个单链表类模板的定义。,template class List/定义通用单链表类模板List,有一个模板参数T public: List(); /声明构造函数 void Add(T ,2) 在类定义体外定义成员函数,如果在类定义体外定义成员函数时,如果该成员函数中有模板参数,则需先进行模板声明,而且用类模板名,而不是用类名来限定函数名,即在函数名前的类名后缀上“”。其一般形式为: template 函数返回值类型 类名:成员函数名(形参表) /函数体 ,例:类模板List中成员函数Add()和Remov
19、e()在类体外定义。,template void List:Add(T / 将新结点的地址赋给头指针 template void List:Remove(T,例:,List intList; 表示将类模板List的类型参数T全部替换成int 型,从而创建一个具体的整型链表类,并生成该具体类的一个对象intList。 List charList; 表示将类模板List的类型参数T全部替换成char 型,从而创建一个具体的字符链表类,并生成该具体类的一个对象charList。,比较:类模板与模板类的区别。,类模板是模板的定义,不是一个实实在在的类,定义中用到通用类型参数。 模板类是实实在在的类定义
20、,是类模板的实例化。类定义中参数被实际类型所代替。 例: 见例exec11.5。,3. 类模板的派生,既可以从类模板派生出类模板,也可以派生出普通类(非模板类)。主要有以下几种形式: 从类模板派生出类模板; 从类模板派生出普通类; 从普通类派生出类模板。,1) 从类模板派生出类模板,从类模板派生出新的类模板的格式如下所示: template class Base ; template class Derived: public Base ; 与定义一般派生类的格式类似,只是在指出它的父类时要加上模板参数。如,Base 。,例:见例exec11.6。,2) 从类模板派生出普通类,从类模板派生出一
21、个普通类的格式如下所示: template class Base ; class Derived: public Base ; 首先,作为新派生出来的普通类的父类,必须是类模板实例化后生成的模板类。例如上面的Base; 其次,在派生类定义之前不需要模板声明语句template 。,例:见例exec11.7。,3) 从普通类派生出类模板,在声明一个类模板时,可以尽可能将类模板中与虚拟类型参数无关的成员剥离出来,构成一个普通类,作为类模板的基类。因此,从普通类派生出类模板的情况也是十分常见的。 例: class Base ; template class Derived:public Base T
22、 data; ,模板的派生甚至可以继承一个未知的基类,也就是说,继承哪个基类由模板参数决定。 例: 见例exec11.8。,template class Derived:public T public: Derived():T() cout x; Derived y; Derived z; return 0; ,小 结,模板的概念: 是实现代码重用机制的一种工具,它可以实现类型参数化,即把类型定义为参数,从而实现代码的可重用性。 模板的分类:函数模板和类模板 函数模板和模板函数 函数模板的定义和使用方法; 函数模板与模板函数的区别。 类模板和模板类 类模板的定义和使用方法; 类模板与模板类的区别; 类模板的派生(3种形式)。,思考题:,1已知 void Sort(int a,int size); void Sort(double a,int size); 是一个函数模板的两个实例,其功能是将数组a中的前size个元素按从小到大顺序排列。试设计这个函数模板。,#include using namespace std; template T Sum(T *ar
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2024年度广告发布合同的投放要求与效果评估2篇
- 04版健身中心设备采购与安装合同2篇
- 2024年度七源知识产权商业秘密许可合同
- 2024年度企业销售激励机制劳动合同
- 2024年度汽车销售退货政策合同3篇
- 2024年度智能医疗系统开发及部署合同
- 2024年度艺人经纪合同-影视行业
- 2024年度供应链管理咨询合作协议
- 2024年度白酒生产原料采购合同
- 2024年度甲乙双方关于纺织工厂建设的借款合同
- 经济法:国有资产法律制度试题及答案四
- 2020年四川省公务员考试《行测》真题及答案
- 川教版四年级英语上册全册练习含答案
- 谷歌合作协议书
- 一例ANCA相关性血管炎患者的护理查房
- “变废为宝从我做起”科学调查体验活动方案【9篇】
- 无人机山区配送可行性研究
- 延安医院电子报告
- JB T 6527-2006组合冷库用隔热夹芯板
- 2024年江苏省高中学业水平考试合格考生物试卷试题(含答案详解)
- 2024年全国初中数学联合竞赛试题参考答案及评分标准
评论
0/150
提交评论