回顾一下模板
来源:互联网 发布:小米笔记本office软件 编辑:程序博客网 时间:2024/06/05 03:49
--------------------------------------------比特科技整理--------------------------------------------
- 本节目标
- 泛型编程
- 模板函数&类模板
- 非类型模板参数&模板的模板参数
- 模板的特化
- 模板的分离编译
- 概念
模板是泛型编程的基础。所谓泛型编程就是编写与类型无关的逻辑代码,是一种复用的方式。模板分为模板函数和模板类。
- 模板函数
假设现在要实现一个比较两个数是否相等的重载函数。
boolIsEqual(intleft,intright){ returnleft==right;}boolIsEqual(conststring&left,conststring&right){ returnleft==right;}voidtest1(){ strings1("s1"),s2("s2"); cout<<IsEqual(s1,s2)<<endl; cout<<IsEqual(1,1)<<endl;}...
如果还要比较int/char等等类型就都要分别实现一下,相似的代码重复度非常高。
函数模板格式:
template <class 形参名1, class 形参名2, class 形参名n>
返回类型 函数名(参数列表)
{...}
模板形参的定义既可以使用class,也可以使用typename,含义是相同的。
模板函数登场,定义一个就搞定了。
template<typenameT>boolIsEqual(constT&left,constT&right){ returnleft==right;}voidtest1(){ strings1("s1"),s2("s2"); cout<<IsEqual(s1,s2)<<endl; cout<<IsEqual(1,1)<<endl;}
从汇编的角度看模板函数的推演
- 模板参数匹配及显示实例化
template<typenameT>boolIsEqual(constT&left,constT&right){ returnleft==right;}voidtest1(){ cout<<IsEqual(1,1)<<endl; //cout<<IsEqual(1,1.2)<<endl; //模板参数不匹配 cout<<IsEqual<int>(1,1.2)<<endl; //显示实例化 cout<<IsEqual<double>(1,1.2)<<endl; // 显示实例化}
- 重载函数模板
boolIsEqual(constint&left,constint&right){ returnleft==right;}template<typenameT>boolIsEqual(constT&left,constT&right){ returnleft==right;}template<typenameT1,typenameT2>boolIsEqual(constT1&left,constT2&right){ returnleft==right;}voidtest1(){ cout<<IsEqual(1,1)<<endl; cout<<IsEqual<int>(1,1)<<endl; cout<<IsEqual(1,1.2)<<endl;}
- 模板类
普通类顺序表的定义
typedefintDataType;//typedef char DataType;classSeqList{private: DataType*_data; int_size; int_capacity;};template<typenameT>classSeqList{private: T*_data; int_size; int_capacity;};
类模板的格式
template<class 形参名1, class 形参名2, ...class 形参名n>
class 类名
{ ... };
- 模板类
// 动态顺序表template<typenameT>classSeqList{public: SeqList(); ~SeqList();private: int_size; int_capacity; T*_data;};template<typenameT>SeqList<T>::SeqList() :_size(0) ,_capacity(10) ,_data(newT[_capacity]){}template<typenameT>SeqList<T>::~SeqList(){ delete[]_data;}voidtest1(){ SeqList<int>sl1; SeqList<double>sl2;}
- 模板参数--实现容器适配器
template<typenameT>classSeqList{private: int_size; int_capacity; T*_data;};// template <class T, class Container>template<classT,classContainer=SeqList<T> >//缺省参数classStack{public: voidPush(constT&x); voidPop(); constT&Top(); boolEmpty();private: Container _con;};voidTest(){ Stack<int>s1; Stack<int,SeqList<int>>s2; //思考下面这种使用场景会怎样? Stack<int,SeqList<char>>s3;}模板的模板参数--容器适配器template<typenameT>classSeqList{private: int_size; int_capacity; T*_data;};// template <class T, template<class> class Container>template<classT,template<class>class Container=SeqList>//缺省参数classStack{public: voidPush(constT&x); voidPop(); constT&Top(); boolEmpty();private: Container<T>_con;};voidTest(){ Stack<int>s1; Stack<int,SeqList>s2;}
- 非类型的类模板参数
// 静态顺序表//template<typename T, size_t MAX_SIZE>template<typenameT,size_tMAX_SIZE= 10>//带缺省模板参数classSeqList{public: SeqList();private: T_array[MAX_SIZE]; int_size;};template<typenameT,size_tMAX_SIZE>SeqList<T,MAX_SIZE>::SeqList() :_size(0){}voidTest(){ SeqList<int>s1; SeqList<int, 20>s2;}
- 非类型的模板函数参数
template<classT,intvalue>T Add(constT&x){ returnx+value;}浮点数和类对象是不允许作为非类型模板参数的//template<class T, string name>template<classT,doubleMaxSize>classTest{private: double_value;};
- 类模板的特化
全特化
</pre><pre name="code" class="cpp">
template<typenameT>classSeqList{public: SeqList(); ~SeqList();private: int_size; int_capacity; T*_data;};template<typenameT>SeqList<T>::SeqList() :_size(0) ,_capacity(10) ,_data(newT[_capacity]){ cout<<"SeqList<T>"<<endl;}template<typenameT>SeqList<T>::~SeqList(){ delete[]_data;}template<>classSeqList<int>{public: SeqList(intcapacity); ~SeqList();private: int_size; int_capacity; int*_data;};//特化后定义成员函数不再需要模板形参SeqList<int>::SeqList(intcapacity) :_size(0) ,_capacity(capacity) ,_data(newint[_capacity]){ cout<<"SeqList<int>"<<endl;}//特化后定义成员函数不再需要模板形参SeqList<int>::~SeqList(){ delete[]_data;}voidtest1(){ SeqList<double>sl2; SeqList<int>sl1(2);}
- 偏特化(局部特化)
template<typename T1,typename T2>classData{public: Data();private: T1_d1; T2_d2;};template<typename T1,typename T2>Data<T1,T2>::Data(){ cout<<"Data<T1, T2>"<<endl;}//局部特化第二个参数template<typenameT1>classData<T1,int>{public: Data();private: T1_d1; int_d2;};template<typenameT1>Data<T1,int>::Data(){ cout<<"Data<T1, int>"<<endl;}ps:下面的例子可以看出,偏特化并不仅仅是指特殊部分参数,而是针对模板参数更进一步的条件限制所设计出来的一个特化版本。//局部特化两个参数为指针类型template<typenameT1,typenameT2>classData<T1*,T2*>{public: Data();private: T1_d1; T2_d2; T1*_d3; T2*_d4;};template<typenameT1,typenameT2>Data<T1*,T2*>::Data(){ cout<<"Data<T1*, T2*>"<<endl;}//局部特化两个参数为引用template<typenameT1,typenameT2>classData<T1&,T2&>{public: Data(constT1&d1,constT2&d2);private: constT1&_d1; constT2&_d2; T1*_d3; T2*_d4;};template<typenameT1,typenameT2>Data<T1&,T2&>::Data(constT1&d1,constT2&d2) :_d1(d1) ,_d2(d2){ cout<<"Data<T1&, T2&>"<<endl;}voidtest2(){ Data<double,int>d1; Data<int,double>d2; Data<int*,int*>d3; Data<int&,int&>d4(1, 2);}
模板的全特化和偏特化都是在已定义的模板基础之上,不能单独存在。
- 模板的分离编译
解决办法:
- 在模板头文件 xxx.h 里面显示实例化->模板类的定义后面添加 templateclassSeqList<int>; 一般不推荐这种方法,一方面老编译器可能不支持,另一方面实例化依赖调用者。(不推荐)
- 将声明和定义放到一个文件 "xxx.hpp" 里面,推荐使用这种方法。
【分离编译的扩展阅读】
http://blog.csdn.net/pongba/article/details/19130
- 模板总结
优点:
缺点:
- 模板复用了代码,节省资源,更快的迭代开发,C++的标准模板库(STL)因此而产生。
- 增强了代码的灵活性。
- 模板让代码变得凌乱复杂,不易维护,编译代码时间变长。
- 出现模板编译错误时,错误信息非常凌乱,不易定位错误。
0 0
- 回顾一下模板
- 回顾一下IPv9
- 回顾一下“快速排序”
- 回顾一下这个寒假
- 回顾一下多态
- 回顾一下排序
- (27)回顾一下
- 那,回顾一下
- 回顾一下web
- 一起回顾一下linux常用命令
- 回顾一下选择和冒泡
- 回顾 记录一下webpart 开发
- Java初始化顺序(回顾一下)
- 回顾一下数据结构线性表
- 回顾一下shell脚本1
- 回顾一下基础的细节
- 回顾一下近来的坑
- poi 开发回顾 模板读取
- 【Codeforces725F】Family Photos {贪心}
- 猫都能学会的Unity3D Shader入门指南(二)
- easyUI的databox取值
- 【转载】通过 FUNCTION NET_DUE_DATE_GET 得到MIRO付款日期(DUE ON DATE)
- SQLCookBook第三章学习日记9
- 回顾一下模板
- linux du命令参数及用法详解---linux统计磁盘空间大小命令
- Vijos P1056 图形面积
- Unity3d 基于NGUI的虚拟摇杆实现
- PHP命名空间的名称解析规则
- ZooKeeper
- AVAudioPlayer实现音乐播放+歌词与播放进度同步
- maven报错解决方案集
- XCODE jsonMODEL对换数据