C++word模板使用类的使用问题

3148人阅读
1编译器如何处理模板
编译器遇到模板的实例化时,如Grid&Spread& b,则为Spread编写另一个Grid类。会使用Spread代替模板定义中的所有的T,来编写Grid模板的Spread版的代码,有点类似宏。
在为多种数据类型实例化模板时,由于编译器会给每种数据类型都生成一个模板代码的副本,所以为多种不同的数据类型实例化模板可能会导致代码膨胀。
2模板代码在文件之间的分布
2.1在头文件中定义模板
2.2在源文件中定义模板
/*---------------------------------------------------------*/
template&typename T&
clase Grid
#include &Grid.cpp&
/*-----------------------------------------------------------------*/
3.模板参数
与在构造函数中指定无类型参数相比,在模板列表指定无类型参数(诸如int和指针这类的常规参数)的主要优点是,代码在编译之前就已经知道了参数的值了。编译器是通过在编译前替换参数来为模板化方法生成代码的。因此在实现中可以使用常规的二维数组,而不用动态分配数组。
/*----------------------------------------------*/
template &typename T,int WIDTH, int HEIGHT&
// 要设定默认参数的方法为 template &typename T,int WIDTH=0, int HEIGHT=0&
class Grid
protected:
T mCell[WIDTH][HEIGHT]
/*-----------------------------------*/
Grid&int ,10,10& myG
4.方法模板
不能模板化虚方法和析构函数。
注意的一点:成员模板不会取代同名的非模板成员,由于编译器生成的代码可能有不同版本,这个规则导致了复制构造函数和operator=会存在问题。如果编写了复制构造函数和operator=的模板化版本,并去掉了非模板化的构造函数和operator=,编译器不会为同一类型的赋值运算调用这些新的模板化构造函数和operator=。相反,编译器会生成一个复制构造函数和operator=,来完成两个同类型的创建和赋值,而这并不是你想要的。因此,还必须要保留老的非模板化复制构造函数和operator=。
(这个在工程中是经常遇到的,具体见下面的示例代码)
5 模板的特殊化
可以为特定类型提供其他的类模板实现。例如,你可能针对char * 的Grid行为是无意义的。网格当前存储的是指针类型的浅副本。对于char * ,字符串的深复制可能才有意义,那么模板的特殊化就是为某个特定类型编写模板
Gird&int &myGrid1 ;//use original Grid template
Gird&char *& myG//use the char * specialization
(这个在工作中还没有遇到)
6.从模板类派生子类
实例代码:
模板代码:
template &typename T&
&&& inline sp() : m_ptr(0) {printf(&this is defult construct!\n&); }
&&& sp(T* other);
&&& sp(const sp&T&& other);
&&& template&typename U& sp(U* other);
&&& template&typename U& sp(const sp&U&& other);
&&& ~sp();
&&& // Assignment
&&& sp& operator = (T* other);
&&& sp& operator = (const sp&T&& other);
&&& template&typename U& sp& operator = (const sp&U&& other);
&&& template&typename U& sp& operator = (U* other);
&&& // Accessors
&&& inline T&&&&&& operator* () const { return *m_ }
&&& inline T*&&&&& operator-& () const { return m_ }
&&& inline T*&&&&& get() const&&&&&&&& { return m_ }
&&& // Operators
private:&&&
&&& template&typename Y&
&&& T*&&&&&&&&&&&&& m_
// ---------------------------------------------------------------------------
template&typename T&
sp&T&::sp(T* other)
&&& : m_ptr(other)
printf(&this is construct !\n&);
template&typename T&
sp&T&::sp(const sp&T&& other)
&&& : m_ptr(other.m_ptr)
printf(&this is copy!\n&);
template&typename T&
sp&T&::~sp()
printf(&this desdory!\n&);
template&typename T&
sp&T&& sp&T&::operator = (const sp&T&& other) {
&&& printf(&this is operator =\n&);
template&typename T& template&typename U&
sp&T&& sp&T&::operator = (const sp&U&& other)
&&& printf(&this is different sp&U& type opterator=!\n&);
template&typename T& template&typename U&
sp&T&& sp&T&::operator = (U* other)
printf(& this is different U type opterator=!\n&);
//-----------------------------------------------------------------------
测试代码:
#include &iostream&
#include &sp.h&
class audio
&&&&&&& void my_print(){ cout&&& hello!\n&&&};
protected:
int main(void)
&&&&&&& sp&audio&
&&&&&&& sp&audio& myaudio2;
&&&&&&& sp&int&
&&&&&&& myaudio=myaudio2;
&&&&&&& audio *ttyy=new audio();
&&&&&&& ttyy-&my_print();
&&&&&&& sp&audio& myaudio3(ttyy);
&&&&&&& sp&audio& myaudio4;
&&&&&&& myaudio4=
&&&&&&& int *x;
&&&&&&& sp&audio& myaudio5;
&&&&&&& myaudio5=x;
&&&&&&& sp&audio& tty=
&&&&&&& /*sp&int&
&&&&&&& sp&int&ls
&&&&&&& my=*/
return (0);
//-------------------------------------------------------
输出信息:
this is defult construct!
this is defult construct!
this is defult construct!
this is operator =
this is construct !
this is defult construct!
this is different sp&U& type opterator=!
this is defult construct!
this is different U type opterator=!
this is copy!
this desdory!
this desdory!
this desdory!
this desdory!
this desdory!
this desdory!
this desdory!
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:42167次
排名:千里之外
转载:34篇
(1)(1)(1)(1)(5)(3)(21)(8)C++中的类模板详细讲述 - Out Man - 博客园
我的博客搬家到:http://blog.csdn.net/assemble8086
此博客以后会很少用了
一、类模板定义及实例化
1. 定义一个类模板:
1 template&class 模板参数表&2 3 class 类名{4 5 // 类定义......6 7 };
其中,template 是声明类模板的关键字,表示声明一个模板,模板参数可以是一个,也可以是多个,可以是类型参数 ,也可以是非类型参数。类型参数由关键字class或typename及其后面的标识符构成。非类型参数由一个普通参数构成,代表模板定义中的一个常量。
1 template&class type,int width&2 3 //type为类型参数,width为非类型参数4 5 class G
(1)如果在全局域中声明了与模板参数同名的变量,则该变量被隐藏掉。
(2)模板参数名不能被当作类模板定义中类成员的名字。
(3)同一个模板参数名在模板参数表中只能出现一次。
(4)在不同的类模板或声明中,模板参数名可以被重复使用。
1 typedef string 2
3 template&class type,int width& 4
5 class Graphics 6
9//node不是string类型10 11 typedef double//错误:成员名不能与模板参数type同名12 13 };14 15 template&class type,class type&//错误:重复使用名为type的参数16 17 class R18 19 template&class type& //参数名&type&在不同模板间可以重复使用20 21 class R
(5)在类模板的前向声明和定义中,模板参数的名字可以不同。
1 // 所有三个 Image 声明都引用同一个类模板的声明 2
3 template &class T& class I 4
5 template &class U& class I 6
7 // 模板的真正定义 8
9 template &class Type&10 11 class Image { //模板定义中只能引用名字&Type&,不能引用名字&T&和&U& };
(6)类模板参数可以有缺省实参,给参数提供缺省实参的顺序是先右后左。
1 template &class type, int size = 1024&2 3 class I4 5 template &class type=double, int size &6 7 class Image;
(7)类模板名可以被用作一个类型指示符。当一个类模板名被用作另一个模板定义中的类型指示符时,必须指定完整的实参表
1 template&class type& 2
3 class Graphics 4
7 Graphics *//在类模板自己的定义中不需指定完整模板参数表 8
9 };10 11 template &calss type&12 13 void show(Graphics&type& &g)14 15 {16 17 Graphics&type& *pg=&g;//必须指定完整的模板参数表18 19 }
2.类模板实例化
定义:从通用的类模板定义中生成类的过程称为模板实例化。
例:Graphics&int&
类模板什么时候会被实例化呢?
①当使用了类模板实例的名字,并且上下文环境要求存在类的定义时。
②对象类型是一个类模板实例,当对象被定义时。此点被称作类的实例化点。
③一个指针或引用指向一个类模板实例,当检查这个指针或引用所指的对象时。
1 template&class Type& 2
3 class Graphics{}; 4
5 void f1(Graphics&char&);// 仅是一个函数声明,不需实例化 6
7 class Rect
9 {10 11   Graphics&double&&// 声明一个类模板引用,不需实例化12 13   Graphics&int&// si是一个Graphics类型的对象,需要实例化类模板14 15 }16 17 int main(){18 19   Graphcis&char&*// 仅声明一个类模板指针,不需实例化20 21   f1(*sc);//需要实例化,因为传递给函数f1的是一个Graphics&int&对象。22 23   int iobj=sizeof(Graphics&string&);//需要实例化,因为sizeof会计算Graphics&string&对象的大小,为了计算大小,编译器必须根据类模板定义产生该类型。24 25 }
3.非类型参数的模板实参
①绑定给非类型参数的表达式必须是一个常量表达式。
②从模板实参到非类型模板参数的类型之间允许进行一些转换。包括左值转换、限定修饰转换、提升、整值转换。
③可以被用于非类型模板参数的模板实参的种类有一些限制。
1 Template&int* ptr& class Graphics{&&.}; 2
3 Template&class Type,int size& class Rect{&&..}; 4
5 const int size=1024; 6
7 Graphics&&size& bp1;//错误:从const int*-&int*是错误的。 8
9 Graphics&0& bp2;//错误不能通过隐式转换把0转换成指针值10 11 const double db=3.1415;12 13 Rect&double,db& fa1;//错误:不能将const double转换成int.14 15 unsigned int fasize=255;16 17 Rect&String, fasize& fa2;//错误:非类型参数的实参必须是常量表达式,将unsigned改为const就正确。18 19 Int arr[10];20 21 Graphics&arr&//正确
二、类模板的成员函数
①类模板的成员函数可以在类模板的定义中定义(inline函数),也可以在类模板定义之外定义(此时成员函数定义前面必须加上template及模板参数)。
②类模板成员函数本身也是一个模板,类模板被实例化时它并不自动被实例化,只有当它被调用或取地址,才被实例化。
1 template&class type& 2
3 Class Graphics{ 4
5 Graphics(){&}//成员函数定义在类模板的定义中 6
7 void out(); 8
9 };10 11 template&class type&//成员函数定义在类模板定义之外12 13 void Graphics&type&::out(){&}
三、类模板的友元声明
类模板中可以有三种友元声明:
1.非模板友元类或友元函数
1 class Graphics{void out();}; 2
3 Template&class T& 4
5 Class Rect{ 6
7 friend class G//类Graphics、函数 8
9 friend void create();// create、 out是类模板10 11 friend void Graphics::out();// Rect所有实例的友元12 13 };
2、绑定的友元类模板或函数模板。
3、非绑定的友元类模板或函数模板。
第二种声明表示类模板的实例和它的友元之间是一种一对一的映射关系。
第三种声明表示类模板的实例和它的友元之间是一种一对多的映射关系。
例:绑定的友元模板
1 template&class type& 2
3 void create(Graphics&type&); 4
5 template&class type& 6
7 class Graphics{ 8
9 friend void create&type&(Graphics&type&);10 11 };
例:非绑定的友元模板
1 template&class type&2 3 class Graphics{4 5 template&class T&6 7 friend void create(Graphics&T&);8 9 };
注意:当把非模板类或函数声明为类模板友元时,它们不必在全局域中被声明或定义,但将一个类的成员声明为类模板友元,该类必须已经被定义,另外在声明绑定的友元类模板或函数模板时,该模板也必须先声明。
1 template &class T& 2
3 class A { 4
5 private: 6
7 friend class B&T&; //错误:类B必须先声明 8
9 };10 11 template &class T&12 13 class B{};
四、类模板的静态数据成员、嵌套类型
1.类模板的静态数据成员
①静态数据成员的模板定义必须出现在类模板定义之外。
②类模板静态数据成员本身就是一个模板,它的定义不会引起内存被分配,只有对其实例化才会分配内存。
③当程序使用静态数据成员时,它被实例化,每个静态成员实例都与一个类模板实例相对应,静态成员的实例引用要通过一个类模板实例。
1 template&class type& 2
3 class Graphics{ 4
5 static Graphics * 6
7 static const 8
9 };10 11 template&class type&12 13 Graphics&type& * Graphics&type&::next=0;14 15 template&class type&16 17 type Graphics&type&::item=NULL;18 19 //静态成员定义分为两部分:前一部分是类型,比如Graphics&type&*,后一部分是名称和值,比如Graphics&type&::next=0;
2.类模板的嵌套类型
①在类模板中允许再嵌入模板,因此类模板的嵌套类也是一个模板,它可以使用外围类模板的模板参数。
②当外围类模板被实例化时,它不会自动被实例化,只有当上下文需要它的完整类类型时,它才会被实例化。
③公有嵌套类型可以被用在类定义之外,这时它的名字前必须加上类模板实例的名字。
1 template&class type& 2
3 class Graphics{ 4
5 public: 6
7 template&class T& 8
9 class Rect{void out(type a,T b);};10 11 };12 13 Graphics&int&::Rect&double&14 15 //引用公有嵌套类型必须加上类模板实例名字
五、成员模板
定义:成员定义前加上template及模板参数表。
①在一个类模板中定义一个成员模板,意味着该类模板的一个实例包含了可能无限多个嵌套类和无限多个成员函数.
②只有当成员模板被使用时,它才被实例化.
③成员模板可以定义在其外围类或类模板定义之外.
1 template&class type& 2
3 class Graphics&type&{ 4
5 public:template&class T& 6
7 class Rect{void out(type a,T b);};}; 8
9 template&class Gtype& template&class TT&10 11 void Graphics&Gtype&::Rect&TT&::out(Gtype a,TT b){}//成员模板被定义在类模板定义之外(要根上完整模板实参)12 13 Graphics&int&的实例可能包括下列嵌套类型:14 15 Graphics&int&::Rect&double&16 17 Graphics&int&::Rect&string&
注意:类模板参数不一定与类模板定义中指定的名字相同。
六、类模板的编译模式
1.包含编译模式
这种编译模式下,类模板的成员函数和静态成员的定义必须被包含在&要将它们实例化&的所有文件中,如果一个成员函数被定义在类模板定义之外,那么这些定义应该被放在含有该类模板定义的头文件中。
2.分离编译模式
这种模式下,类模板定义和其inline成员函数定义被放在头文件中,而非inline成员函数和静态数据成员被放在程序文本文件中。
1 //------Graphics.h--------- 2
3 export template&class type& 4
5 Class Graphics 6
7 {void Setup(const type &);}; 8
9 //-------Graphics.c------------10 11 #include &Graphics.h&12 13 Template &class type&14 15 Void Graphics&type&::Setup(const type &){&}16 17 //------user.c-----18 19 #include &Graphics.h&20 21 Void main()22 23 {Graphics&int& *pg=new Graphics&int&;24 25 Int ival=1;26 27 //Graphics&int&::Setup(const int &)的实例(下有注解)28 29 Pg-&Setup(ival);30 31 }
Setup的成员定义在User.c中不可见,但在这个文件中仍可调用模板实例Graphics&int&::Setup(const int &)。为实现这一点,须将类模声明为可导出的:当它的成员函数实例或静态数据成员实例被使用时,编译器只要求模板的定义,它的声明方式是在关键字template前加关键字export
3.显式实例声明
当使用包含编译模式时,类模板成员的定义被包含在使用其实例的所有程序文本文件中,何时何地编译器实例化类模板成员的定义,我们并不能精确地知晓,为解决这个问题,标准C++提供了显式实例声明:关键字template后面跟着关键字class以及类模板实例的名字。
1 #include &Graphics.h&2 3 Template class Graphics&int&;//显式实例声明
显式实例化类模板时,它的所有成员也被显式实例化。
七、类模板的特化及部分特化
1.类模板的特化
先看下面的例子:
1 Template&class type&2 3 Class Graphics{4 5 Public:void out(type figure){&}};6 7 Class Rect{&};
如果模板实参是Rect类型,我们不希望使用类模板Graphics的通用成员函数定义,来实例化成员函数out(),我们希望专门定义Graphics&Rect&::out()实例,让它使用Rect里面的成员函数。
为此,我们可以通过一个显示特化定义,为类模板实例的一个成员提供一个特化定义。
格式:template&& 成员函数特化定义
下面为类模板实例Graphics&Rect&的成员函数out()定义了显式特化:
Template&& void Graphics&Rect&::out(Rect figure){&}
①只有当通用类模板被声明后,它的显式特化才可以被定义。
②若定义了一个类模板特化,则必须定义与这个特化相关的所有成员函数或静态数据成员,此时类模板特化的成员定义不能以符号template&&作为打头。(template&&被省略)
③类模板不能够在某些文件中根据通用模板定义被实例化,而在其他文件中却针对同一组模板实参被特化。
2.类模板部分特化
如果模板有一个以上的模板参数,则有些人就可能希望为一个特定的模板实参或者一组模板实参特化类模板,而不是为所有的模板参数特化该类模板。即,希望提供这样一个模板:它仍然是一个通用的模板,只不过某些模板参数已经被实际的类型或值取代。通过使用类模板部分特化,可以实现这一点。
1 template&int hi,int wid&2 3 Class Graphics{&};4 5 Template&int hi&//类模板的部分特化6 7 Class Graphics&hi,90&{&};
格式:template&模板参数表&
①部分特化的模板参数表只列出模板实参仍然未知的那些参数。
②类模板部分特化是被隐式实例化的。编译器选择&针对该实例而言最为特化的模板定义&进行实例化,当没有特化可被使用时,才使用通用模板定义。
例:Graphics&24,90&
它即能从通用类模板定义被实例化,也能从部分特化的定义被实例化,但编译器选择的是部分特化来实例化模板。
③类模板部分特化必须有它自己对成员函数、静态数据成员和嵌套类的定义。
八、名字空间和类模板
类模板定义也可以被放在名字空间中。例如:
1 Namespace cplusplus_primer{ 2
3 Template&class type& 4
5 Class Graphics{&}; 6
7 Template&class type& 8
9 Type create()10 11 {&}12 13 }
当类模板名字Graphics被用在名字空间之外时,它必须被名字空间名cplusplus_primer限定修,或者通过一个using声明或指示符被引入。例如:
1 Void main()2 3 {4 5 using cplusplus_primer::G6 7 Graphics&int& *pg=new Graphics&int&;8 9 }
注意:在名字空间中声明类模板也会影响该类模板及其成员的特化和部分特化声明的方式,类模板或类模板成员的特化声明必须被声明在定义通用模板的名字空间中(可以在名字空间之外定义模板特化)。
一个关于队列的例子,下面将其代码整理如下:
1 #include "iostream.h"
3 template &class Type& class QueueI
5 template &class Type&
7 class Queue {
9 public: 10
11 friend ostream& operator&&(ostream &os,const Queue&Type& &q); 12
13 Queue() : front( 0 ), back ( 0 ) { } 14
15 ~Queue(){} 16
17 void add( const Type & ); 18
19 bool is_empty() const 20
23 return front == 0; 24
27 Type remove(); 28
29 private: 30
31 QueueItem&Type& * 32
33 QueueItem&Type& * 34
37 template &class Type& 38
39 class QueueItem 40
43 public: 44
45 QueueItem(Type val){item=next=0;} 46
47 friend class Queue&Type&; 48
49 friend ostream& operator&&(ostream &os,const Queue&Type& &q); 50
51 friend ostream& operator&&(ostream &os,const QueueItem&Type& &qi); 52
55 private: 56
59 QueueItem * 60
63 template &class Type& 64
65 void Queue&Type&::add(const Type &val) 66
69 QueueItem&Type& *pt =new QueueItem&Type&(val); 70
71 if ( is_empty() ) 72
73 front = back = 74
75 else 76
79 back-&next = 80
81 back = 82
87 template &class Type& 88
89 Type Queue&Type&::remove() 90
93 if ( is_empty() ) 94
97 cerr && "remove() on empty queue \n"; 98
99 exit(-1);100 101 }102 103 QueueItem&Type& *pt =104 105 front = front-&106 107 Type retval = pt-&108 109110 111 return112 113 }114 115 template &class Type&116 117 ostream& operator&&(ostream &os, const Queue&Type& &q) //输出队列成员118 119 {120 121 os && "& ";122 123 QueueItem&Type& *p;124 125 for ( p = q. p = p-&next )126 127 os && *p && & ;//用到了Queue和QueueItem的私有成员,因此需将此运算符重128 129 //载函数声明为Queue和QueueItem的友元,书上没有将此函数声明为QueueItem130 131 os && & &&;//的友元。132 133 return134 135 }136 137 template &class Type&138 139 ostream& operator&& ( ostream &os, const QueueItem&Type& &qi )140 141 {142 143 os && qi.//用到了QueueItem的私有成员,因此需将此运算符重载函数声明144 145 //为QueueItem的友元146 147 return148 149 }150 151 void main()152 153 {154 155 Queue&int&156 157 cout && qi &&158 159 int160 161 for ( ival = 0; ival & 10; ++ival )162 163 qi.add( ival );164 165 cout && qi &&166 167 int err_cnt = 0;168 169 for ( ival = 0; ival & 10; ++ival ) {170 171 int qval = qi.remove();172 173 if ( ival != qval ) err_cnt++;174 175 }176 177 cout && qi &&178 179 if ( !err_cnt )180 181 cout && "!! queue executed ok\n";182 183 else cout && &?? queue errors: " && err_cnt &&184 185 }C++类模板的使用 - 下载频道
- CSDN.NET
&&&&C++类模板的使用
C++类模板的使用
类的模板,模板函数,类模板构造函数和析构函数的定义
嵌到我的页面
<input type="text" readonly="true" value="">
若举报审核通过,可奖励20下载分
被举报人:
huxing_xinfang
举报的资源分:
请选择类型
资源无法下载
资源无法使用
标题与实际内容不符
含有危害国家安全内容
含有反动色情等内容
含广告内容
版权问题,侵犯个人或公司的版权
*详细原因:
您可能还需要
课程资源下载排行

我要回帖

更多关于 word模板使用 的文章

 

随机推荐