进阶篇_STL详解(函数模板特化,类模板特化,用模板实现自己的通用算法)
来源:互联网 发布:现货外盘软件 编辑:程序博客网 时间:2024/06/05 02:26
STL ~= 容器 + 算法 + 迭代器。容器用于容纳数据,算法用于处理数据,迭代器像胶水一样将容器和算法紧密地结合在一起。算法通过迭代器来定位和操控容器中的元素,事实上,每个容器都有自己的迭代器,只有容器自己才知道如何访问自己的元素,这使得迭代器就像一个指向容器中元素的普通指针一样。
#include <iostream>#include <vector>#include <algorithm>using namespace std;//工资统计,计算收入大于1000的员工人数 int main(){vector<int> vecSalary;int put;do{cin>>put;if(0 == put)break;vecSalary.push_back(put);}while(true);int total = count_if(vecSalary.begin(), vecSalary.end(), bind2nd(greater<int>(), 1000)); //count_if:返回区间中满足指定条件的元素数目。 cout<<total<<endl; return 0;}容器vector的使用不像数组那样固定分配内存,其可以根据用户的输入动态地增长,保证内存空间的合理利用,又可以让程序具有很大的可扩张性,处理很大范围内的数据。由此可得到STL的主要几个好处:封装很多常用的数据结构(容器),提供很多常用的通用算法(算法),调试程序更加安全和方便,支持跨平台(使用STL的C++代码可以轻松地移植到其他平台上)。模板是实现代码重用的一种重要机制,它可以实现类型的参数化,把类型定义为参数,而STL正是借助模板的威力建构起来的。
函数模板
如果说把函数比作一个箱子,每个箱子都是专用的(实现具体的不同功能),那函数模板就是一个万能箱子,它可以用来装各种东西,处理各种类型的数据。比如当编译器发现一个函数模板的调用后,将根据实参的实际数据类型来确认是否匹配函数模板中对应的形参,然后生成一个重载函数,称该重载函数为模板函数。根据参数类型的不同,一个函数模板可以随时变成各种不同的重载函数,从而实现对各种数据类型的处理。函数模板可以用来创建一个通用功能的函数,以支持各种不同的数据类型,简化重载函数的设计。函数模板的声明与使用如下:
#include <iostream>using namespace std;//模板函数范例 template <typename T> //type理解为模板函数中的一个参数,代表抽象的数据类型 T max(const T a, const T b){ return a>b ? a : b;}int main(){ int a = 10; int b = 20; int c = std::max<int>(a, b); //注意写法,不加std::,会error cout<<c<<endl; //output: 20 float aa = 0.3; float bb = 0.4; float cc = std::max(aa, bb); //max<float>的<...>不写编译器会自动分析生成相应的重载函数,但是有时候必须要指明类型参数以满足特殊需求,比如max<string> cout<<cc<<endl; //output: 0.4 string aaa = "abcd"; string bbb = "cde"; string ccc = std::max(aaa, bbb); cout<<ccc<<endl; //output: cde,这里输出cde,不是返回最长的而是返回字符较大的,所以如果需要应该对模板函数进行特化,实现特定类型的模板函数 return 0;}
特化模板函数,实现特定类型的string模板函数,希望返回最长的字符串:
#include <iostream>using namespace std;//特化函数模板string范例template <typename T>//普通函数模板 T max(const T a, const T b){return a>b ? a : b;}template <>//特化string的函数模板 string max<string>(const string a, const string b)//注意这里及以上的写法格式 {return a.size()>b.size() ? a : b; }int main(){int a = 5;int b = 4;float c = 5.3;float d = 4.4;cout<<std::max(a, b)<<endl<<std::max(c, d)<<endl;//output: 5 5.3string x = "chen";string y = "aisda";cout<<std::max(x, y)<<endl; //用普通函数模板output: cde,返回字符较大的cout<<std::max<string>(x, y)<<endl; //用特化函数模板output: chen,返回字符串最长的 return 0;}
类模板
#include <iostream>using namespace std;//特化类模板范例//定义一个比较两个数的类模板compare<T> template <typename T>//typename所定义的标识符实际上就是类模板的参数,模板参数可以是一个可以是多个 class compare{public:compare(T a, T b): m_a(a), m_b(b){}public:T min(){return m_a > m_b ? m_b : m_a;}T max(){return m_a > m_b ? m_a : m_b;}private:T m_a;T m_b;};int main(){compare<int> intcompare(2, 3);cout<<intcompare.max()<<" > "<<intcompare.min()<<endl;compare<float> floatcompare(2.2, 4.4);cout<<floatcompare.max() <<" > "<<floatcompare.min()<<endl;return 0;}/*output: 3 >2 4.4 > 2.2*/
模板的实例化
模板的实例化分为:隐式实例化和显式实例化。
compare<int> intcompare(2, 3);//隐式实例化大多数都采用隐式实例化,具体的显式实例化如果需要时自行再查,注意的是显式实例化类时,所有的类成员也必须实例化。
用模板实现自己的通用算法
#include <iostream>using namespace std;/*软件谁集中,通常有一个撤销undo和恢复redo的通用功能*//*动作容器模板类,使用T作为模板参数*/template <class T>class actioncontainer{public:actioncontainer(){m_nredo = 0;m_nundo = 0;}void add(T value);//向容器中添加新动作 T redo();//恢复上一步动作 T undo();//撤销上一步动作 private:int m_nredo;int m_nundo;const static int ACTION_SIZE = 5;T m_redoAction[ACTION_SIZE]; //使用数组记录恢复和撤销的动作,数组元素的类型也是模板参数,它在类模板实例化时才确定 T m_undoAction[ACTION_SIZE];};/*模板类的成员函数实现*///向容器中添加动作,这里的T可以是一个基本数据类型,也可以是一个自定义类型 template <class T>void actioncontainer<T>::add(T value){//判断容器中的动作数目是否超过容器的容量 if(m_nundo >= ACTION_SIZE){m_nundo = ACTION_SIZE - 1;for(int i=0; i<ACTION_SIZE; ++i)m_undoAction[i] = m_undoAction[i+1];//将容器中已有的动作前移一个位置 }//将新动作添加到容器中m_undoAction[m_nundo++] = value; }//撤销上一步动作 template <class T>T actioncontainer<T>::undo(){m_redoAction[m_nredo++] = m_undoAction[--m_nundo];//将撤销的动作复制到恢复数组中 return m_undoAction[m_nundo];//返回撤销的动作 }//恢复上一步动作 template <class T>T actioncontainer<T>::redo(){m_undoAction[m_nundo++] = m_redoAction[--m_nredo];//将撤销的动作复制到恢复数组中 return m_redoAction[m_nredo];//返回撤销的动作 }int main(){actioncontainer<int> intaction;//定义一个int类型的动作容器,这样这个动作容器就可以容纳int类型的数据 intaction.add(1);//向容器中添加新的动作,也就是整数 intaction.add(2);intaction.add(3);intaction.add(4); int nundo = intaction.undo(); //撤销上一步动作,这时,nundo的值为4nundo = intaction.undo();//再次撤销身上一步动作,nundo的值为3int nredo = intaction.redo(); //恢复上一步动作,这时,nredo的值为3nredo = intaction.redo();//再次恢复身上一步动作,nredo的值为4return 0;}
以上代码定义了一个类模板actioncontainer<T>,这个类可以容纳动作(add)并且能够进行撤销(undo)和恢复(redo)动作。在这个模板类的内部,使用了两个数组来分别记录撤销和恢复的动作。这里的动作实际上是广义上的一种数据类型,它可以是一个基本数据类型比如int float,也可以是自己定义的数据类型,这样就使得这个动作容器具有广泛的通用性,可以处理各种数据类型。在这个动作容器类模板actioncontainer<T>中,还定义了它的成员函数,用于操作这个容器中的数据,其中包括添加新的动作到容器中、撤销或恢复动作等。当然,这里成员函数同样是对抽象的模板参数进行操作,其中并不涉及具体的数据类型,也就是说,这些操作与具体的数据类型无关。
- 进阶篇_STL详解(函数模板特化,类模板特化,用模板实现自己的通用算法)
- (函数/类模板)的(偏特化/全特化)
- 函数模板的特化
- 模板函数的特化
- 函数模板的特化
- 函数模板的特化
- 函数模板的特化
- 函数模板的特化
- 类模板的特化
- 类模板的特化
- C++模板的特化详解(函数模版特殊,类模版特化)
- 模板函数和类的特化以及偏特化
- 类模板的特化和偏特化
- 类模板的 全特化、偏特化
- 类模板的特化,偏特化
- 模板的特化、偏特化
- 函数模板特化(一)
- 模板的特化(特化和偏特化)
- mac 下使用wireshark监听网络上的数据
- Android 快速开发(一),封装一个 TopBarBaseActivity
- python——爬虫学习——正则表达式与Re库-(4)
- 一 : BlockingQueue接口
- UML 用例图中<<include>>,<<extends>>,<<uses>>的区别
- 进阶篇_STL详解(函数模板特化,类模板特化,用模板实现自己的通用算法)
- ORA-12505, TNS:listener does not currently know of SID given in connect descriptor
- Apache 2.4 局域网发布网站
- vue2.0——v-model指令
- 2017年五一单身狗准备怎么过?
- 动态代理JDKf方式InvocationHandler、Proxy
- Flex布局新旧混合写法详解(兼容微信)
- 卷积神经网络图像风格转移 Image StyleTransfer Using Convolutional Neural Networks
- C#中String类的几个方法(IndexOf、LastIndexOf、Substring)