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

加入VIP,免费下载
 

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

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

下载须知

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

版权提示 | 免责声明

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

模版深入详解.docx

1、模版深入详解在C+发明阶段,C+之父Stroustrup和贝尔实验室的C+小组对原先的宏方法进行了修订,对其进行了简化并将它从预处理范围移入了编译器。这种新的代码替换装置被称为模板,而且它变现了完全不同的代码重用方法:模板对源代码重用,而不是通过继承和组合重用对象代码。当用户使用模板时,参数由编译器来替换,这非常像原来的宏方法,却更清晰,更容易使用。模板使类和函数可在编译时定义所需处理和返回的数据类型,一个模板并非一个实实在在的类或函数,仅仅是一个类和函数的描述。由于模板可以实现逻辑相同、数据类型不同的程序代码复制,所以使用模板机制可以减轻编程和维护的工作量和难度。模板一般分为模板函数和类模板

2、。以所处理的数据类型的说明作为参数的类就叫类模板,或者模板类,而以所处理的数据类型的说明作为参数的函数,则称为函数模板。本文包含函数目标和类模板,有些可能会交错设计两个模块的细节。1.函数模板函数模板定义了参数化的非成员函数,这使得程序员能够用不同类型的参数调用相同的函数,由编译器决定调用哪一种类型,并且从模板中生成相应的代码。定义:Template类型参数表返回类型 函数名 (形参表)函数体简单实例,调用函数打印字符串或数字等。普通函数形式:1. #include 2. #include 3. void printstring(const std:string& str) 4. 5. std

3、:cout str std:endl; 6. 7. int main() 8. 9. std:string str(Hello World); 10. printstring(str); 11. return 0; 12. /输出:Hello World 模板函数形式:1. #include 2. #include 3. using namespace std; 4. template void print(const T& var) 5. 6. cout var endl; 7. 8. int main() 9. 10. string str(Hello World); 11. const

4、int num=1234; 12. print(str); 13. print(num); 14. return 0; 15. 16. /输出:Hello World 17. / 1234 可以看出使用模板后的函数不仅可以输出字符串形式还可以输出数字形式的内容。上面两个例子介绍了函数模板的简单使用方法,但只有一个参数,如果需要多个参数,相应的函数模板应采用以下形式定义:Template类型1 变量1,类型2 变量2 ,返回类型 函数名 (形参表)函数体现在,为了看到模板时如何称为函数的,我们假定min()函数接受各种类型的参数,并找出其中的最小者,如果不采用模板技术,则只能接受一个特定类型的参

5、数,如果希望也能接受其他类型的参数,就需要对每一种类型的参数都定义一个同功能的函数,其实为函数的重载,这里不在讨论,但这将是一件非常让人麻烦的事情。如:普通定义:1. #include 2. / 定义多态函数,找出三个整数中最小的数 3. int min0(int ii, int jj, int kk) 4. 5. int temp; 6. if(iijj)&(iikk)temp=ii; 7. else if(jjii)&(jjkk)temp=jj; 8. else temp=kk; 9. return temp; 10. 11. / 定义多态函数,找出三个小数中最小的数 12. float

6、min1(float ii, float jj, float kk) 13. 14. float temp; 15. if(iijj)&(iikk)temp=ii; 16. else if(jjii)&(jjkk)temp=jj; 17. else temp=kk; 18. return temp; 19. 20. 21. / 定义多态函数,找出三个子符中最小的字符 22. char min2(char ii, char jj, char kk) 23. 24. char temp; 25. if(iijj)&(iikk) temp=ii; 26. else if(jjii)&(jjkk)te

7、mp=jj; 27. elsetemp=kk; 28. return temp; 29. 30. 31. void main() 32. 33. int temp1=min0(100,20,30); 34. couttemp1endl; 35. float temp2=min1(10.60,10.64,53.21); 36. couttemp2endl; 37. char temp3=min2(c,a,C); 38. couttemp3endl; 39. 40. /以换行形式输出20 10.6 C 使用模板:1. #include 2. / 定义函数模板,找出三个值中最小的值,与数据类型无关

8、3. template 4. T min(T ii, T jj, T kk) 5. 6. T temp; 7. if(iijj)&(iikk)temp=ii; 8. else if(jjii)&(jjkk)temp=jj; 9. else temp=kk; 10. return temp; 11. 12. / 下面是主函数 13. void main() 14. 15. coutmin(100,20,30)endl; 16. coutmin(10.60,10.64,53.21)endl; 17. coutmin(c,a,C)endl; 18. 输出结果同上,但可以清楚的看到二者之间的工作量大小

9、之差距。函数模板功能非常强大,但是有时候可能会陷入困境,加入待比较的函数模板没有提供正确的操作符,则程序不会对此进行编译。为了避免这种错误,可以使用函数模板和同名的非模板函数重载,这就是函数定制。函数模板与同名的非模板函数重载必须遵守以下规定:寻找一个参数完全匹配的函数,如有,则调用它如果失败,寻找一个函数模板,使其实例化,产生一个匹配的模板函数,若有,则调用它如果失败,再试低一级的对函数重载的方法,例如通过类型转换可产生的参数匹配等,若找到匹配的函数,调用它如果失败,则证明这是一个错误的调用现在用上例的模板函数比较两个字符串,但会出现问题:1. #include 2. / 定义函数模板,找出

10、三个值中最小的值,与数据类型无关 3. template 4. T min(T ii, T jj, T kk) 5. 6. T temp; 7. if(iijj)&(iikk) temp=ii; 8. else if(jjii)&(jjkk) temp=jj; 9. else temp=kk; 10. return temp; 11. 12. void main() 13. 14. coutmin(anderson,Washington,Smith)endl; 15. 输出anderson 与实际结果不否,原因在于编译器会生成对字符串指针做比较的函数,但比较字符串和比较字符串指针是不一样的,为

11、了解决此问题,我们可以定制函数模板,如:1. #include 2. #include 3. using namespace std; 4. / 定义函数模板,找出三个值中最小的值,与数据类型无关 5. template 6. T min(T ii, T jj, T kk) 7. 8. T temp; 9. if(iijj)&(iikk) temp=ii; 10. else if(jjii)&(jjkk) temp=jj; 11. else temp=kk; 12. return temp; 13. 14. /非模板函数重载 15. const char* min(const char* ch

12、1, const char* ch2,const char* ch3) 16. 17. const char* temp; 18. int result1 = strcmp(ch1,ch2); 19. int result2 = strcmp(ch1,ch3); 20. int result3 = strcmp(ch2,ch1); 21. int result4 = strcmp(ch2,ch3); 22. if(result10)&(result20) temp = ch1; 23. else if(result30)&(result40) temp=ch2; 24. else temp=c

13、h3; 25. return temp; 26. 27. void main() 28. 29. coutmin(100,20,30)endl; 30. coutmin(10.60,10.64,53.21)endl; 31. coutmin(c,a,C)endl; 32. coutmin(anderson,Washington,Smith)endl; 33. 在VS 2010中,最后一行会输出Smith, 与结果先符。注意:若上例在VC+ 6.0 中运行,其结果最后一行仍会输出anderson,读者可自己上机查看情况并分析原因。下面给出一些实例:1. #ifndef HEADER_MY 2.

14、#define HEADER_MY 3. #include 4. #include 5. template 6. T fromString(const std:string &s) 7. 8. std:istringstream is(s); 9. T t; 10. ist; 11. return t; 12. 13. template 14. std:string toString(const T &s) 15. 16. std:ostringstream t; 17. ts; 18. return t.str(); 19. 20. 21. #endif 22. 23. 24. #inclu

15、de HEADER.h 25. #include 26. #include 27. using namespace std; 28. int main() 29. 30. int i = 1234; 31. cout i = toString(i) n; 32. float x = 567.89; 33. cout x = toString(x) n; 34. complex c(1.0, 2.0); 35. cout c = toString(c) n; 36. cout endl; 37. i = fromString(string(1234); 38. cout i = i endl;

16、39. x = fromString(string(567.89); 40. cout x = x endl; 41. c = fromString complex (string(1.0,2.0); 42. cout c = c endl; 43. return 0; 44. 模板实参推演当函数模板被调用时,对函数实参类型的检查决定了模板实参的类型和值的这个过程叫做模板实参推演。如template void h(T a); h(1); h(0.2);第一个调用因为实参是int型的,所以模板形参T被推演为int型,第二个T的类型则为double。在使用函数模板时,请注意以下几点:在模板被实例化

17、后,就会生成一个新的实例,这个新生成的实例不存在类型转换。比如有函数模板template void H(T a);int a=2; short b=3;第一个调用H(a)生成一个int型的实例版本,但是当调用h(b)的时候不会使用上次生成的int实例把short转换为int,而是会另外生成一个新的short型的实例。在模板实参推演的过程中有时类型并不会完全匹配,这时编译器允许以下几种实参到模板形参的转换,这些转换不会生成新的实例。数组到指针的转换或函数到指针的转换:比如template void h(T * a),int b3=1,2,3;h(b);这时数组b和类型T *不是完全匹配,但允许从

18、数组到指针的转换因此数组b被转换成int *,而类型形参T被转换成int,也就是说函数体中的T被替换成int。限制修饰符转换:即把const或volatile限定符加到指针上。比如template void h(const T* a),int b=3; h(&b);虽然实参&b与形参const T*不完全匹配,但因为允许限制修饰符的转换,结果就把&b转换成const int *。而类形型参T被转换成int。如果模板形参是非const类型,则无论实参是const类型还是非const类型调用都不会产生新的实例。到一个基类的转换(该基类根据一个类模板实例化而来):比如tessmplateclass

19、A; template class B:public A; template void h(A& m),在main函数中有B n; h(n);函数调用的子类对象n与函数的形参A不完全匹配,但允许到一个基类的转换。在这里转换的顺序为,首先把子类对象n转换为基类对象A,然后再用A去匹配函数的形参A&,所以最后T2被转换为int,也就是说函数体中的T将被替换为int。对于函数模板而言不存在h(int,int)这样的调用,不能在函数调用的参数中指定模板形参的类型,对函数模板的调用应使用实参推演来进行,即只能进行h(2,3)这样的调用,或者int a, b; h(a,b)。模板实参推演实例,说明内容较长

20、,采用注释形式,但代码较乱:1. #include 2. using namespace std; 3. templatevoid h(T a)cout h()typeid(T).name()endl; /带有一个类型形参T的模板函数的定义方法,typeid(变量名).name()为测试变量类型的语句。 4. templatevoid k(T a,T b)T c;cout k()typeid(T).name()endl; /注意语句T c。模板类型形参T可以用来声明变量,作为函数的反回类型,函数形参等凡是类类型能使用的地方。 5. template void f(T1 a, T2 b)cout

21、 f()typeid(T1).name(),typeid(T2).name()endl; /定义带有两个类型形参T1,T2的模板函数的方法template void g(const T* a)T b;cout g()typeid(b).name()endl; 6. /template void g() /错误,默认模板类型形参不能用于函数模板,只能用于类模板上。 7. /main函数开始 8. int main() 9. / templatevoid h() /错误,模板的声明或定义只能在全局,命名空间或类范围内进行。即不能在局部范围,函数内进行。 10. /函数模板实参推演示例。 11. /

22、 h(int); /错误,对于函数模板而言不存在h(int,int)这样的调用,不能在函数调用的参数中指定模板形参的类型,对函数模板的调用应使用实参推演来进行,即只能进行h(2,3)这样的调用,或者int a, b; h(a,b)。 12. /h函数形式为:templatevoid h(T a) 13. h(2);/输出 h() int使用函数模板推演,在这里数值2为int型,所以把类型形参T推演为int型。 14. h(2.0);/输出 h() double,因为2.0为double型,所以将函数模板的类型形参推演为double型 15. /k函数形式为:templatevoid k(T a

23、,T b) 16. k(2,3);/输出 k() int 17. /k(2,3.0);错误,模板形参T的类型不明确,因为k()函数第一个参数类型为int,第二个为double型,两个形参类型不一致。 18. /f函数的形式为:template void f(T1 a, T2 b) 19. f(3,4.0);/输出 f() int,double,这里不存在模板形参推演错误的问题,因为模板函数有两个类型形参T1和T2。在这里将T1推演为int,将T2推演为double。 20. int a=3;double b=4; 21. f(a,b); /输出同上,这里用变量名实现推板实参的推演。 22. /

24、模板函数推演允许的转换示例,g函数的形式为template void g(const T* a) 23. int a12=1,2;g(a1); /输出 g() int,数组的地址和形参const T*不完全匹配,所以将a1的地址T &转换为const T*,而a1是int型的,所以最后T推演为int。 24. g(&b); /输出 g() double,这里和上面的一样,只是把类型T转换为double型。 25. h(&b); /输出 h() double *这里把模参类型T推演为double *类型。 26. return 0; 27. 函数模板的显示实例化隐式实例化:比如有模板函数temp

25、late void h(T a)。h(2)这时h函数的调用就是隐式实例化,既参数T的类型是隐式确定的。函数模板显示实例化声明:其语法是:template 函数反回类型 函数名 (函数形参表); 注意这是声明语句,要以分号结束。例如:template void h (int a);这样就创建了一个h函数的int 实例。再如有模板函数template T h( T a),注意这里h函数的反回类型为T,显示实例化的方法为template int h(int a); 把h模板函数实例化为int 型。对于给定的函数模板实例,显示实例化声明在一个文件中只能出现一次。在显示实例化声明所在的文件中,函数模板的

26、定义必须给出,如果定义不可见,就会发生错误。注意:不能在局部范围类显示实例化模板,实例化模板应放在全局范围内,即不能在main函数等局部范围中实例化模板。因为模板的声明或定义不能在局部范围或函数内进行。显示模板实参:1、显示模板实参:适用于函数模板,即在调用函数时显示指定要调用的时参的类型。2、格式:显示模板实参的格式为在调用模板函数的时候在函数名后用尖括号括住要显示表示的类型,比如有模板函数template void h(T a, T b)。则h(2, 3.2)就把模板形参T显示实例化为double类型。3、显示模板实参用于同一个模板形参的类型不一致的情况。比如template void h

27、(T a, T b),则h(2, 3.2)的调用会出错,因为两个实参类型不一致,第一个为int 型,第二个为double型。而用h(2, 3.2)就是正确的,虽然两个模板形参的类型不一致但这里把模板形参显示实例化为double类型,这样的话就允许进行标准的隐式类型转换,即这里把第一个int 参数转换为double类型的参数。4、显示模板实参用法二:用于函数模板的反回类型中。例如有模板函数template T1 h(T2 a, T3 b),则语句int a=h(2,3)或h(2,4)就会出现模板形参T1无法推导的情况。而语句int h(2,3)也会出错。用显示模板实参就参轻松解决这个问题,比如h(2,3)即把模板形参T1实例化为int 型,T2和T3也实例化为int 型。5、显示模板实参用法三:应用于模板函数的参数中没有出现模板形参的情况。比如templatevoid h()如果在main函数中直接调用h函数如h()就会出现无法推演类型形参T的类型的错误,这时用显示模板实

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

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