ImageVerifierCode 换一换
格式:DOCX , 页数:12 ,大小:140.95KB ,
资源ID:4240034      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/4240034.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(c++模板.docx)为本站会员(b****5)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

c++模板.docx

1、c+模板一、什么是模板 在C+编程中,当我们需要获取两个变量之间的较大值时,考虑到变量的类型可能会是int、double等,最常用的方法往往是通过重载函数,实现不同类型的函数版本:cpp view plaincopy1. intMax(intlhs,intrhs)2. 3. return(lhsrhs)?lhs:rhs;4. 5. 6. doubleMax(doublelhs,doublerhs)7. 8. return(lhsrhs)?lhs:rhs;9. 此时,当我们接到新的需求,需要获取两个char类型的变量之间的较大值时,我们就会再添加一个char类型重载函数:cpp view pla

2、incopy1. charMax(charlhs,charrhs)2. 3. return(lhsrhs)?lhs:rhs;4. 每 当新增一种的类型的需求,又需要实现多一个重载函数,无形中增加了开发人员的工作,当函数逻辑比较复杂,而且比较庞大时,也容易出现错误。从上面的代码可 以看出,三个版本的重载函数除了类型不一样之外,逻辑基本一致,完成的功能也是相同的,因此,如果能有一个通用的函数,抽取出这些相同的代码逻辑,将可以 大大减少代码的重复,提高代码的重用性。此时,使用C+的模板就可以很好的解决这些问题,通过模板,可以使得开发人员写出更通用、更灵活、类型无关的代 码。二、模板的分类和格式 C+

3、模板(template),主要分为函数模板和类模板。2.1 函数模板2.1.1 函数模板的格式和使用 template 返回类型 函数名(参数列表) /函数体 模板定义以关键字template开始,后接以括号括住的模板形参表,其中class是关键字,在这里class可以使用typename 代替,括号中的模板形参使用逗号进行分隔。下面使用函数模板实现前面的求较大值函数:cpp view plaincopy1. template2. TMax(constT&lhs,constT&rhs)3. 4. return(lhsrhs)?lhs:rhs;5. cpp view plaincopy1. /测

4、试用例:2. inta=34,b=257;3. doublec=1.4,d=4.4;4. chare=b,f=k;5. 6. coutMax(a,b)endl;/调用了int版本的模板函数,输出为:2577. coutMax(c,d)endl;/调用了double版本的模板函数,输出为:4.48. coutMax(e,f)endl;/调用了char版本的模板函数,输出为:k 当对上面定义的函数模板进行编译时,类型T就会被实际传入的类型所代替,例如Max(a, b)中a和b是int型,这时函数模板Max中的形参T就会被int代替,并实例化一个模板函数Max(const int &lhs, con

5、st int &rhs);同理,当实际传入的类型为double、char等其他类型时,就会实例化相应类型的模板函数,从而实现了类型无关的泛型编程。2.1.2 函数模板一般不对实参进行隐式类型转换 好奇的你可能会问,前面几个调用都是用同一种类型,当调用Max(a, b),其中a为int类型,b为double类型,这样会得到正确的结果吗?cpp view plaincopy1. #include2. usingnamespacestd;3. 4. template5. TMax(constT&lhs,constT&rhs)6. 7. return(lhsrhs)?lhs:rhs;8. 9. 10.

6、 intmain(intargc,constchar*argv)11. 12. inta=10;13. doubleb=5.3;14. coutMax(a,b)endl;15. 从 编译器的出错信息可以看出,上面的例子在模板形参推导的过程中出现了错误。这是由于编译器在编译时,会将函数模板的形参解析为首先遇到的类型,以上例子 中,编译器首先遇到的是int类型,函数模板的形参就被解析为int类型,同时函数模板一般不对实参进行隐式类型转换(除了非const引用或指针到 const引用或指针的转换、数组或函数到指针的转换),参数需要完全匹配,因此以上例子不能通过编译。 解决方案有两种: 第一:强制类型

7、转换cpp view plaincopy1. inta=10;2. doubleb=5.3;3. coutMax(a,(int)b)endl;/输出为:10 第二:在函数模板中增加一种形参类型cpp view plaincopy1. template2. T1Max(constT1&lhs,constT2&rhs)3. 4. return(lhsrhs)?lhs:rhs;5. 6. 7. inta=10;8. doubleb=10.3;9. coutMax(a,b)endl;/输出为:10 上面的情况,返回的是T1类型,当我们需要返回T2类型的时候,就把返回类型改为T2就可以。这样改来改去实在

8、不方便,那能不能让调用者决定返回的类型呢?答案是肯定的,只要再加一种形参类型就可以了。cpp view plaincopy1. template2. T1Max(constT2&lhs,constT3&rhs)3. 4. return(lhsrhs)?lhs:rhs;5. 6. 7. inta=10;8. doubleb=10.3;9. coutMax(a,b)endl; 上面的函数模板可以让调用者决定返回的类型,但是却不可以通过编译,以下为对应的出错信息: 出错的原因是,编译器可以根据传入的实参推导出T2和T3的类型,却没有其它信息可以让编译器推导出T1的类型,因此,在这种情况下,我们需要在

9、调用的时候显式指定T1的类型:cpp view plaincopy1. inta=10;2. doubleb=10.3;3. coutMax(a,b)endl;/输出为:10.32.1.3 模板函数 vs 重载函数 在前面说到,通过模板函数可以避免了重载函数的一些问题,在这里大家会不会问一句,模板函数是否可以重载?答案也是一如既往的肯定。cpp view plaincopy1. template2. TMax(constT&lhs,constT&rhs)3. 4. return(lhsrhs)?lhs:rhs;5. 6. 7. template8. TMax(constT&arg1,const

10、T&arg2,constT&arg3)9. 10. Ttemp=(arg1arg2)?arg1:arg2;11. return(temparg3)?temp:arg3;12. 13. 14. inta=1,b=2,c=3;15. Max(a,b);/调用两个参数的模板函数16. Max(a,b,c);/调用三个参数的模板函数 模板函数不但可以重载,而且还可以与非模板函数进行重载,下面列出的是模板函数和非模板函数的重载:cpp view plaincopy1. template2. TMax(constT&lhs,constT&rhs)3. 4. return(lhsrhs)?lhs:rhs;5

11、. 6. 7. intMax(intlhs,intrhs)8. 9. return(lhsrhs)?lhs:rhs;10. 11. 12. inta=1,b=2;13. Max(a,b);/调用非模板函数 上面的例子中,实际调用的是非模板函数,而不是模板函数,这就涉及到模板函数和非模板函数的匹配顺序问题。引用C+ Primer的一段描述: C+中,函数模板与同名的非模板函数重载时,应遵循下列调用原则: a. 寻找一个参数完全匹配的函数,若找到就调用它。 b. 寻找一个函数模板,若找到就将其实例化生成一个匹配的模板函数并调用它。 c. 若上面两条都失败,则使用函数重载的方法,通过类型转换产生参数

12、匹配,若找到就调用它。 d. 若上面三条都失败,还没有找都匹配的函数,则这个调用是一个错误的调用。 简单来说,就是非模板函数匹配优先于模板函数,没有非模板函数时,选择最匹配和最特化的模板函数。2.2 类模板2.2.1 类模板的格式 template class 类名 /. ; 类模板的定义与函数模板类似,也是以关键字template开头,后接模板参数列表。cpp view plaincopy1. template2. classUtility3. 4. pubic:5. Utility(Targ):m_value(arg)6. TAdd(Targ)const;7. TAdd(Tlhs,Trhs

13、);8. 9. private:10. Tm_value;11. ;12. 13. template14. TUtility:Add(constT&arg)const15. 16. returnarg+m_value;17. 18. 19. template20. TUtility:Add(Tlhs,Trhs)21. 22. returnlhs+rhs;23. 24. 25. Utilityutil(1);coututil.Add(2)endl;/输出为:326. coututil.Add(2,3.5)endl;/输出为:5 类 模板每次实例化的时候,都会产生一个独立的类类型,上例产生的就是一

14、个int类型的Uitility类型。在创建类对象时,一定要显式指定类模板的模板形 参的类型,如上例的Utility util(1),否则编译会出错,而且不允许出现Utility util(1),类模板形参不能进行实参类型推导,必须显式指定类型。 上例中的util.Add(2, 3.5)调用能通过编译,实参3.5会被隐式转换为int,并能得到正确结果,而在模板函数中却会出错,函数模板和类模板对于隐式类型转换的要求是不一致的。 三、模板特化 模板特化分为全特化和偏特化两种。其中,类模板可以全特化和偏特化,函数模板只能全特化,函数的模板只能重载,没有偏特化。3.1 函数模板全特化cpp view p

15、laincopy1. /函数模板通用版本2. template3. intCompare(constTlhs,constTrhs)4. 5. if(lhsrhs)return-1;6. if(rhslhs)return1;7. return0;8. 当参数类型为指针类型时,上面定义的模板可能不能正常工作,通常两个字符串比较都是按字典顺序进行比较,但是上面定义模板,当参数类型为指针类型时,就会变成比较两个地址的大小。因此,当具体到字符串指针类型时,就需要下面的特例化模板定义:cpp view plaincopy1. /函数模板全特化版本2. template3. intCompare(const

16、char*lhs,constchar*rhs)4. 5. returnstrcmp(lhs,rhs);6. 3.2 类模板全特化和偏特化cpp view plaincopy1. /类模板通用版本2. template3. classCompare4. 5. public:6. boolIsEqual(Tlhs,Trhs)7. 8. return(lhs=rhs);9. 10. ;11. 12. /类模板全特化版本13. template14. classCompare15. 16. public:17. boolIsEqual(constchar*lhs,constchar*rhs)18. 1

17、9. returnstrcmp(lhs,rhs);20. 21. ; 以上例子展示了类模板的全特化,下面展示类模板的偏特化:cpp view plaincopy1. /类模板通用版本2. template3. classCompare4. 5. /.6. ;7. 8. /类模板偏特化版本9. template10. classCompare11. 12. /.13. ;四、使用模板的注意事项4.1 typename与class的区别 在模板形参列表中,关键字typename和class没有区别,但在某些情况下,typename与class还是有区别的。cpp view plaincopy1.

18、template2. voidFunc()3. 4. T:A*var;/猜一下,是声明一个指针,还是进行一次乘法操作5. 在以上情况下,编译器不确定类型T作用域下的A是一个类型,还是一个静态成员变量,因此需要在模板参数前面加上typename来表明这个A是一个类型(typename可以用来指示后面的名字是一个类型名)。另外,使用typename含义更加清晰,而使用class容易与类定义的class混淆,所以还是推荐是在模板形参列表中使用typename。 4.2 模板声明或定义的范围 模板的声明或定义只能在全局,命名空间或类范围内进行,不能在局部范围,函数内进行,例如不能在main函数中声明或

19、定义一个模板。4.3 template在声明的时候就需要定义 当实现一个类的时候,我们常常会在一个.h文件中声明类结构,然后在一个.cpp文件中定义该类,下面为Utility.h文件:cpp view plaincopy1. #ifndefUTILITY_H2. #defineUTILITY_H3. 4. template5. classUtility6. 7. public:8. TMax(constT&lhs,constT&rhs);9. ;10. 11. #endif 相应的Utility.cpp文件如下:cpp view plaincopy1. #includeUtility.h2.

20、3. template4. TUtility:Max(constT&lhs,constT&rhs)5. 6. return(lhsrhs)?lhs:rhs;7. 以下代码在main.cpp文件中,将会对前面定义的Utility类进行调用:cpp view plaincopy1. #include2. #includeUtility.h3. 4. intmain(intargc,constchar*argv)5. 6. Utilityutil;7. coututil.Max(2,3)endl;8. return0;9. 编译结果如下图所示: C+编程思想第15章(第300页)说明了上例出错的原因

21、: 模 板定义很特殊。由template 处理的任何东西都意味着编译器在当时不为它分配存储空间,它一直处于等待状态直到被一个模板实例告知。在编译器和连接器的某一处,有一机制能去掉指定模板 的多重定义。所以为了容易使用,几乎总是在头文件中放置全部的模板声明和定义。 可行的解决方法主要有三种: 第一种:把模板的声明和定义放在一起 第二种:在Utility.h文件尾部加上#include Utility.cpp,其实就是第一种方法,只是间接将两个文件拼在一起了。 第三种:C+理论上支持export关键字,以实现模板的分隔编译,本人机器的g+版本为4.7.3,但在使用export关键字时,仍会出现以下问题:总结:模板是C+泛型编程中不可或缺的一部分,在STL(Standard Template Library)中得到广泛的使用。理解了模板,特别是模板的特化和偏特化,也就基本理解了STL中的核心-traits编程,为STL的学习打下了坚实的基础。

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1