Chapter 26.模板与泛型编程

概述

模板是泛型编程的基础
面向对象编程是运行时多态,而泛型编程是编译时多态
模板是在编译时编译器可以自动实例化的

函数模板

template <class/typename  parameter ,class/typename  parameter ,...>//关键字class比较老,typename后来加入C++
//因为相对来讲template是不怎么常用的编程,所以<>这对尖括号会写错,每一个class/typename可能也会忘记写
returnValue function(parameter);
inline函数模板
template <class/typename  parameter ,class/typename  parameter ,...>
inline returnValue function(parameter);

类模板

  1. <span style="font-size:14px;">eg:  
  2. template <class _Tp, class _Alloc = __STL_DEFAULT_ALLOCATOR(_Tp) >  
  3. class list : protected _List_base<_Tp, _Alloc> {</span>  

类模板的使用

要显式指定模板实参
  1. <span style="font-size:14px;">eg:  
  2. list<string></span>  
模板形参
模板形参与变量名差不多
  1. <span style="font-size:14px;">eg:  
  2. template <class _Tp, class _Alloc = __STL_DEFAULT_ALLOCATOR(_Tp) >//在同一形参表中,形参名不能相同,不能都为_Tp,不然没有办法区分  
  3. class vector : protected _Vector_base<_Tp, _Alloc>   
  4. {  
  5.     //形参的作用域和一般类或者一般函数作用域相同,都为template和类体或者函数体(类外定义部分当然也算)  
  6. }  
  7. //模板可只声明,再定义(声明和定义中的形参不一定要相同,和一般函数形参相似)</span>  
模板类型形参

形参为类类型

eg:

template <class _Tp, class _Allocator>
class _Vector_alloc_base<_Tp, _Allocator, true> {
public:
  typedef typename _Alloc_traits<_Tp, _Allocator>::allocator_type
          allocator_type;
非模板类型形参

形参不一定为类类型

  1. <span style="font-size:14px;">eg:  
  2. template <class _Tp,size_t N>  
  3. void printArray(_Tp (&array)[N])  
  4. {  
  5.     for(size_t i = 0; i != N; ++i)  
  6.     {  
  7.         cout<<array[i]<<'\t';  
  8.     }  
  9. }</span>  

编写模板代码时,应该尽量减少对实参的要求

实例化

类/函数模板的实例化都是在使用时才会实例化

模板实参推断

  1. <span style="font-size:14px;">eg:  
  2. Test<int> iT;//类模板形参<int>是必须的,Test<int>才是一个类型  
  3. compare(1,0);//这里叫做模板实参推断,就是从函数实参推断出模板实参类型和值的过程</span>  
数组或函数指针的转换
如果是模板形参是非引用类型,则数组实参将转换成指向数组第一个元素的指针,同样函数实参将转换成指向函数类型的指针
  1. <span style="font-size:14px;">//模板形参为非引用类型  
  2. eg:  
  3. template <typename T> T fobj(T,T);  
  4. int a[10],b[10];  
  5. fobj(a,b);//转换为 fobj(int *,int *)</span>  
  1. <span style="font-size:14px;">//模板形参为引用类型  
  2. eg:  
  3. template <typename T> T fref(const &T,const &T);  
  4. int a[10],b[10];  
  5. fref(a,b);//不能转换 形参为引用时,数组不能转换为指针</span>  
//模板形参为函数指针
  1. <span style="font-size:14px;">eg:  
  2. #include <cstring>  
  3. template<class Value_Type>  
  4. class HashTable  
  5. {  
  6. public:  
  7.     HashTable(bool (*compare_ptr)(const Value_Type obj1, const Value_Type obj2), unsigned long size = 100):  
  8.        isEqual(compare_ptr) {}   
  9. private:  
  10.     bool (*isEqual)(const Value_Type obj1, const Value_Type obj2);  
  11. };  
  12. bool _compare(const char* val1, const char* val2)  
  13. {  
  14.     if (strcmp(val1, val2) == 0)  
  15.         return true;  
  16.     else  
  17.         return false;  
  18. }  
  19. int main()  
  20. {  
  21.     HashTable<const char* > hash(_compare);  
  22. }</span>  

函数模板的显式实参

  1. <span style="font-size:14px;">eg:  
  2. template <class t1,class t2,class t3>  
  3. t1 sum(t1,t2);//如果返回值放第一位,可以如下使用  
  4. sum<long>(123L,456L);  
  5.   
  6. sum(static_cast<int>(s),i);//模板形参不一致导致返回值类型不定时,可以用static_cast<type>来强制转换实参</span>  

模板编译模型

很多编译器都不支持模板声明和定义分离

1.包含编译模型

一般应该把声明和定义都放在.h中
or
在声明之后 #include "实现.cpp"
如果实现是一组内联函数,可把内联函数放在.inl文件中,在.h的末尾加上 #include "xxx.inl"

2.分别编译模型

export关键字
//.h
声明模板
//.cpp
#include <.h>
export 定义模板
//如果是类的话,还可以不一定export 类,可以只export某些类成员
因为编译器支持的比较少,这种separate编译就不着重介绍了

类模板成员

在类外声明类模板成员
template <class T> 类名<T>::模板成员函数(类名 cp);

类模板中的友元声明

1.普通友元
直接声明就行
friend class ClassName;
friend retType function(args);
2.一般模板友元 一对多的关系
template <class Type>
class A
{
template <class T> friend class ClassName;//类模板友元
template <class T> friend retType tempFun(const T&);//函数模板友元
}
A的每一个实例,ClassName和tempFun的所有实例都是友元
3.特定模板友元 一对一的关系
  1. eg:  
  2. //前向声明  
  3. template <class T> class ClassName;  
  4. template <class T> retType tempFun(const T&);  
  5. //特定友元  
  6. template <class T>  
  7. class A  
  8. {  
  9.     friend class ClassName<char *>;  
  10.     friend retType tempFun<char *>(char *const &);  
  11. };  
更一般的形式,T一个类型是友元
  1. //前向声明  
  2. template <class T> class ClassName;  
  3. template <class T> retType tempFun(const T&);  
  4. //特定友元  
  5. template <class Type>  
  6. class A  
  7. {  
  8.     friend class ClassName< Type >;  
  9.     friend retType tempFun< Type >(const  Type &);  
  10. };  
每一个A的实例,ClassName和tempFun都有一个对应的实例是友元
  1. eg:  
  2. A<int> 与 ClassName<int> & tempFun<int>是友元  
关于operator<<重载的小问题
//declare
template <class _Tp> class Queue;
template <class _Tp>
std::ostream& operator<<(std::ostream &os,const Queue<_Tp> &ref);

template <class _Tp>
class QueueItem
{
friend class Queue<_Tp>;
friend std::ostream& operator<< <_Tp> (std::ostream&, const Queue<_Tp>&ref);//这里的<_Tp>使编译发现重载的友元运算符是一个模板

所谓的从形参推断是指在真正调用函数模板时,通过函数形参推断模板形参,这样才推断出是普通的友元函数还是友元函数模板
成员模板
任意类(模板类/普通类)都可以拥有类模板或函数模板成员,就是成员模板,成员模板不能为虚,成员模板遵循常规访问控制
模板类在外部定义成员模板
  1. eg:  
  2. template <class T> template <class Iter>//有两个模板形参表  
  3. void Queue<T>::assign(Iter beg,Iter end)  
  4. {  
  5.       
  6. }  
类模板的static成员
类模板的每一个类型的实例化共享同一static成员
  1. eg:  
  2. template <class T>  
  3. class A  
  4. {  
  5. public:  
  6.     A(){}  
  7.     static std::size_t getCount()  
  8.     {  
  9.         return cnt;  
  10.     }  
  11. private:  
  12.     static std::size_t cnt;  
  13. };  
  14. template <class T>//与普通static成员不一样,要说明是template的  
  15. std::size_t A<T>::cnt=0;  
  16.   
  17. //使用  
  18. A<int> i1,i2,i3;//i1,i2,i3都共享一个cnt;  
  19. A<string> s1;//s1独自共享另一个cnt;  

模板特化

函数模板特化

函数模板只能全特化,无法偏特化,只能重载
函数模板特化之前一般函数模板必须要存在
  1. eg:  
  2. //.h  
  3. template <class _Tp>  
  4. int myCompare(const _Tp &s1,const _Tp &s2)//一般函数模板  
  5. {  
  6. if (s1<s2)  
  7. {  
  8. return -1;  
  9. }  
  10. else if (s2<s1)  
  11. {  
  12. return 1;  
  13. }  
  14. else//s1==s2  
  15. {  
  16. return 0;  
  17. }  
  18. }  
  19.   
  20. template<>  
  21. int myCompare<const char*>(const charconst &s1,const charconst &s2) //全特化模板  
  22. {  
  23. return strcmp(s1,s2);  
  24. }  
  25. //.cpp  
  26. //使用·  
  27. const char *ch1="hello";  
  28. const char *ch2="world";  
  29. cout<<myCompare(ch2,ch1);//return 1  

类模板特化

类模板可以全特化、偏特化也可以只特化某些类成员函数
//全特化
  1. eg:  
  2. //.h  
  3. template <>  
  4. class A<const char*>  
  5. {  
  6. public:  
  7.     void function(const char*);  
  8. };  
  9. //.h中的定义  
  10. template<>  
  11. void A<const char*>::function(const char*)  
  12. {  
  13.     //code here  
  14. }  
//偏特化
  1. eg:  
  2. //一般类模板  
  3. template  <class T1,class T2>  
  4. class A  
  5. {  
  6. };  
  7. //偏特化  
  8. template <class T1>  
  9. class A<T1,int>  
  10. {  
  11. };  
//只特化某些类成员函数
  1. eg:  
  2. //特化声明  
  3. template <>  
  4. void Queue<const char*>::push(const charconst &);  
  5. template <>  
  6. void Queue<const char*>::pop();  
  7. //特化定义  
  8. template <>  
  9. void  Queue<const char*>::push(const charconst &val)  
  10. {  
  11.     char *newChar=new char[strlen(val)+1];  
  12.     strncpy(newChar,val,strlen(val)+1);  
  13.     QueueItem<const char*> *pt=new QueueItem<const char*>(newChar);  
  14.     if(empty())  
  15.     {  
  16.         head=tail=pt;  
  17.     }  
  18.     else  
  19.     {  
  20.         tail->next=pt;  
  21.         tail=pt;  
  22.     }  
  23. }  
  24.   
  25. template <>  
  26. void Queue<const char*>::pop()  
  27. {  
  28.     QueueItem<const char*> *tempForDelete=head;  
  29.     delete head->data;  
  30.     head=head->next;  
  31.     delete tempForDelete;  
  32. }  

                
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值