C++中的类模板详细讲述.docx_第1页
C++中的类模板详细讲述.docx_第2页
C++中的类模板详细讲述.docx_第3页
C++中的类模板详细讲述.docx_第4页
C++中的类模板详细讲述.docx_第5页
已阅读5页,还剩17页未读 继续免费阅读

下载本文档

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

文档简介

一、类模板定义及实例化.定义一个类模板:1 template2 3 class 类名4 5 / 类定义6 7 ;其中,template 是声明类模板的关键字,表示声明一个模板,模板参数可以是一个,也可以是多个,可以是类型参数,也可以是非类型参数。类型参数由关键字class或typename及其后面的标识符构成。非类型参数由一个普通参数构成,代表模板定义中的一个常量。例:1 template2 3 /type为类型参数,width为非类型参数4 5 class Graphics;注意:(1)如果在全局域中声明了与模板参数同名的变量,则该变量被隐藏掉。(2)模板参数名不能被当作类模板定义中类成员的名字。(3)同一个模板参数名在模板参数表中只能出现一次。(4)在不同的类模板或声明中,模板参数名可以被重复使用。 1 typedef string type; 2 3 template 4 5 class Graphics 6 7 8 9 type node;/node不是string类型10 11 typedef double type;/错误:成员名不能与模板参数type同名12 13 ;14 15 template/错误:重复使用名为type的参数16 17 class Rect;18 19 template /参数名”type”在不同模板间可以重复使用20 21 class Round;(5)在类模板的前向声明和定义中,模板参数的名字可以不同。 1 / 所有三个 Image 声明都引用同一个类模板的声明 2 3 template class Image; 4 5 template class Image; 6 7 / 模板的真正定义 8 9 template 10 11 class Image /模板定义中只能引用名字”Type”,不能引用名字”T”和”U” ;(6)类模板参数可以有缺省实参,给参数提供缺省实参的顺序是先右后左。1 template 2 3 class Image;4 5 template 6 7 class Image;(7)类模板名可以被用作一个类型指示符。当一个类模板名被用作另一个模板定义中的类型指示符时,必须指定完整的实参表 1 template 2 3 class Graphics 4 5 6 7 Graphics *next;/在类模板自己的定义中不需指定完整模板参数表 8 9 ;10 11 template 12 13 void show(Graphics &g)14 15 16 17 Graphics *pg=&g;/必须指定完整的模板参数表18 19 类模板实例化定义:从通用的类模板定义中生成类的过程称为模板实例化。例:Graphics gi;类模板什么时候会被实例化呢?当使用了类模板实例的名字,并且上下文环境要求存在类的定义时。对象类型是一个类模板实例,当对象被定义时。此点被称作类的实例化点。一个指针或引用指向一个类模板实例,当检查这个指针或引用所指的对象时。例: 1 template 2 3 class Graphics; 4 5 void f1(Graphics);/ 仅是一个函数声明,不需实例化 6 7 class Rect 8 9 10 11 Graphics& rsd;/ 声明一个类模板引用,不需实例化12 13 Graphics si;/ si是一个Graphics类型的对象,需要实例化类模板14 15 16 17 int main()18 19 Graphcis* sc;/ 仅声明一个类模板指针,不需实例化20 21 f1(*sc);/需要实例化,因为传递给函数f1的是一个Graphics对象。22 23 int iobj=sizeof(Graphics);/需要实例化,因为sizeof会计算Graphics对象的大小,为了计算大小,编译器必须根据类模板定义产生该类型。24 25 3.非类型参数的模板实参要点:绑定给非类型参数的表达式必须是一个常量表达式。从模板实参到非类型模板参数的类型之间允许进行一些转换。包括左值转换、限定修饰转换、提升、整值转换。可以被用于非类型模板参数的模板实参的种类有一些限制。例: 1 Template class Graphics.; 2 3 Template class Rect.; 4 5 const int size=1024; 6 7 Graphics bp1;/错误:从const int*int*是错误的。 8 9 Graphics bp2;/错误不能通过隐式转换把转换成指针值10 11 const double db=3.1415;12 13 Rect fa1;/错误:不能将const double转换成int.14 15 unsigned int fasize=255;16 17 Rect fa2;/错误:非类型参数的实参必须是常量表达式,将unsigned改为const就正确。18 19 Int arr10;20 21 Graphics gp;/正确二、类模板的成员函数要点:类模板的成员函数可以在类模板的定义中定义(inline函数),也可以在类模板定义之外定义(此时成员函数定义前面必须加上template及模板参数)。类模板成员函数本身也是一个模板,类模板被实例化时它并不自动被实例化,只有当它被调用或取地址,才被实例化。 1 template 2 3 Class Graphics 4 5 Graphics()/成员函数定义在类模板的定义中 6 7 void out(); 8 9 ;10 11 template/成员函数定义在类模板定义之外12 13 void Graphics:out()三、类模板的友元声明类模板中可以有三种友元声明:.非模板友元类或友元函数 1 class Graphicsvoid out(); 2 3 Template 4 5 Class Rect 6 7 friend class Graphics;/类Graphics、函数 8 9 friend void create();/ create、 out是类模板10 11 friend void Graphics:out();/ Rect所有实例的友元12 13 ;2、绑定的友元类模板或函数模板。3、非绑定的友元类模板或函数模板。第二种声明表示类模板的实例和它的友元之间是一种一对一的映射关系。如图:第三种声明表示类模板的实例和它的友元之间是一种一对多的映射关系。如图:例:绑定的友元模板 1 template 2 3 void create(Graphics); 4 5 template 6 7 class Graphics 8 9 friend void create(Graphics);10 11 ;例:非绑定的友元模板1 template2 3 class Graphics4 5 template6 7 friend void create(Graphics);8 9 ;注意:当把非模板类或函数声明为类模板友元时,它们不必在全局域中被声明或定义,但将一个类的成员声明为类模板友元,该类必须已经被定义,另外在声明绑定的友元类模板或函数模板时,该模板也必须先声明。例: 1 template 2 3 class A 4 5 private: 6 7 friend class B; /错误:类必须先声明 8 9 ;10 11 template 12 13 class B;四、类模板的静态数据成员、嵌套类型.类模板的静态数据成员要点:静态数据成员的模板定义必须出现在类模板定义之外。类模板静态数据成员本身就是一个模板,它的定义不会引起内存被分配,只有对其实例化才会分配内存。当程序使用静态数据成员时,它被实例化,每个静态成员实例都与一个类模板实例相对应,静态成员的实例引用要通过一个类模板实例。例: 1 template 2 3 class Graphics 4 5 static Graphics *next; 6 7 static const type item; 8 9 ;10 11 template12 13 Graphics * Graphics:next=0;14 15 template16 17 type Graphics:item=NULL;18 19 /静态成员定义分为两部分:前一部分是类型,比如Graphics*,后一部分是名称和值,比如Graphics:next=0;2.类模板的嵌套类型要点:在类模板中允许再嵌入模板,因此类模板的嵌套类也是一个模板,它可以使用外围类模板的模板参数。当外围类模板被实例化时,它不会自动被实例化,只有当上下文需要它的完整类类型时,它才会被实例化。公有嵌套类型可以被用在类定义之外,这时它的名字前必须加上类模板实例的名字。例: 1 template 2 3 class Graphics 4 5 public: 6 7 template 8 9 class Rectvoid out(type a,T b);10 11 ;12 13 Graphics:Rect node;14 15 /引用公有嵌套类型必须加上类模板实例名字五、成员模板定义:成员定义前加上template及模板参数表。要点:在一个类模板中定义一个成员模板,意味着该类模板的一个实例包含了可能无限多个嵌套类和无限多个成员函数只有当成员模板被使用时,它才被实例化.成员模板可以定义在其外围类或类模板定义之外例: 1 template 2 3 class Graphics 4 5 public:template 6 7 class Rectvoid out(type a,T b); 8 9 template template10 11 void Graphics:Rect:out(Gtype a,TT b)/成员模板被定义在类模板定义之外(要根上完整模板实参)12 13 Graphics的实例可能包括下列嵌套类型:14 15 Graphics:Rect16 17 Graphics:Rect注意:类模板参数不一定与类模板定义中指定的名字相同。六、类模板的编译模式1.包含编译模式这种编译模式下,类模板的成员函数和静态成员的定义必须被包含在“要将它们实例化”的所有文件中,如果一个成员函数被定义在类模板定义之外,那么这些定义应该被放在含有该类模板定义的头文件中。2.分离编译模式这种模式下,类模板定义和其inline成员函数定义被放在头文件中,而非inline成员函数和静态数据成员被放在程序文本文件中。例: 1 /-Graphics.h- 2 3 export template 4 5 Class Graphics 6 7 void Setup(const type &); 8 9 /-Graphics.c-10 11 #include “Graphics.h”12 13 Template 14 15 Void Graphics:Setup(const type &)16 17 /-user.c-18 19 #include “Graphics.h”20 21 Void main()22 23 Graphics *pg=new Graphics;24 25 Int ival=1;26 27 /Graphics:Setup(const int &)的实例(下有注解)28 29 Pg-Setup(ival);30 31 Setup的成员定义在User.c中不可见,但在这个文件中仍可调用模板实例Graphics:Setup(const int &)。为实现这一点,须将类模声明为可导出的:当它的成员函数实例或静态数据成员实例被使用时,编译器只要求模板的定义,它的声明方式是在关键字template前加关键字export.显式实例声明当使用包含编译模式时,类模板成员的定义被包含在使用其实例的所有程序文本文件中,何时何地编译器实例化类模板成员的定义,我们并不能精确地知晓,为解决这个问题,标准C+提供了显式实例声明:关键字template后面跟着关键字class以及类模板实例的名字。例:1 #include “Graphics.h”2 3 Template class Graphics;/显式实例声明显式实例化类模板时,它的所有成员也被显式实例化。七、类模板的特化及部分特化1.类模板的特化先看下面的例子:1 Template2 3 Class Graphics4 5 Public:void out(type figure);6 7 Class Rect;如果模板实参是Rect类型,我们不希望使用类模板Graphics的通用成员函数定义,来实例化成员函数out(),我们希望专门定义Graphics:out()实例,让它使用Rect里面的成员函数。为此,我们可以通过一个显示特化定义,为类模板实例的一个成员提供一个特化定义。格式:template 成员函数特化定义下面为类模板实例Graphics的成员函数out()定义了显式特化:Template void Graphics:out(Rect figure)注意:只有当通用类模板被声明后,它的显式特化才可以被定义。若定义了一个类模板特化,则必须定义与这个特化相关的所有成员函数或静态数据成员,此时类模板特化的成员定义不能以符号template作为打头。(template被省略)类模板不能够在某些文件中根据通用模板定义被实例化,而在其他文件中却针对同一组模板实参被特化。2.类模板部分特化如果模板有一个以上的模板参数,则有些人就可能希望为一个特定的模板实参或者一组模板实参特化类模板,而不是为所有的模板参数特化该类模板。即,希望提供这样一个模板:它仍然是一个通用的模板,只不过某些模板参数已经被实际的类型或值取代。通过使用类模板部分特化,可以实现这一点。例:1 template2 3 Class Graphics;4 5 Template/类模板的部分特化6 7 Class Graphics;格式:template注意:部分特化的模板参数表只列出模板实参仍然未知的那些参数。类模板部分特化是被隐式实例化的。编译器选择“针对该实例而言最为特化的模板定义”进行实例化,当没有特化可被使用时,才使用通用模板定义。例:Graphics figure;它即能从通用类模板定义被实例化,也能从部分特化的定义被实例化,但编译器选择的是部分特化来实例化模板。类模板部分特化必须有它自己对成员函数、静态数据成员和嵌套类的定义。八、名字空间和类模板类模板定义也可以被放在名字空间中。例如: 1 Namespace cplusplus_primer 2 3 Template 4 5 Class Graphics; 6 7 Template 8 9 Type create()10 11 12 13 当类模板名字Graphics被用在名字空间之外时,它必须被名字空间名cplusplus_primer限定修,或者通过一个using声明或指示符被引入。例如:1 Void main()2 3 4 5 using cplusplus_primer:Graphics;6 7 Graphics *pg=new Graphics;8 9 注意:在名字空间中声明类模板也会影响该类模板及其成员的特化和部分特化声明的方式,类模板或类模板成员的特化声明必须被声明在定义通用模板的名字空间中(可以在名字空间之外定义模板特化)。一个关于队列的例子,下面将其代码整理如下: 1 #include iostream.h 2 3 template class QueueItem; 4 5 template 6 7 class Queue 8 9 public: 10 11 friend ostream& operator(ostream &os,const Queue &q); 12 13 Queue() : front( 0 ), back ( 0 ) 14 15 Queue() 16 17 void add( const Type & ); 18 19 bool is_empty() const 20 21 22 23 return front = 0; 24 25 26 27 Type remove(); 28 29 private: 30 31 QueueItem *front; 32 33 QueueItem *back; 34 35 ; 36 37 template 38 39 class QueueItem 40 41 42 43 public: 44 45 QueueItem(Type val)item=val;next=0; 46 47 friend class Queue; 48 49 friend ostream& operator(ostream &os,const Queue &q); 50 51 friend ostream& operator(ostream &os,const QueueItem &qi); 52 53 54 55 private: 56 57 Type item; 58 59 QueueItem *next; 60 61 ; 62 63 template 64 65 void Queue:add(const Type &val) 66 67 68 69 QueueItem *pt =new QueueItem(val); 70 71 if ( is_empty() ) 72 73 front = back = pt; 74 75 else 76 77 78 79 back-next = pt; 80 81 back = pt; 82 83 84 85 86 87 template 88 89 Type Queue:remove() 90 91 92 93 if ( is_empty() ) 94 95 96 97 cerr remove() on empty queue n; 98 99 exit(-1);100 101 102 103 QueueItem *pt = front;104 105 front = front-next;106 107 Type retval = pt-item;108 109 delete pt;110 111 return retval;112 113 114 115 template 116 117 ostream& operator(ostream &os, const Queue &q) /输出队列成员1

温馨提示

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

评论

0/150

提交评论