1.什么是泛型编程
所谓泛型编程,就是不依赖于某一具体类型而使代码具有很强适应性的编程范式。我们看下面的求和函数是如何一步步进化成最纯粹的泛型编程的。
最开始,sum
函数是这样子的:
double sum(const std::vector<double> &vec) {
double result = 0.0;
for(const auto e : vec) {
result += e;
}
return result;
}
显然这个函数只适用于std::vector<double>
类型的容器变量,现在我们可以把vector
内部元素抽象成一个模板,正如下面这样的:
template <class T>
T sum(const std::vector<T> &vec, T start) {
for(const auto e : vec) {
start += e;
}
return start;
}
但是函数仍然只适用于std::vector
类型的容器变量,如果想要兼容std::list
等等的其他容器,可以引入迭代器,进一步抽象。
template <class InputIterator, class T>
T sum(InputIterator first, InputIterator last, T start) {
while(first != last) {
start += *first++;
}
return start;
}
这样我们分3
步完成了求和函数的泛型编程,正如你在上面看到的那样,要实现泛型编程,必须理解两个很重要的概念才行——模板
和迭代器
。
2.迭代器
2.1.什么是迭代器
迭代器非常类似于指针,用于访问容器中的各元素,而STL
中的迭代器,常作为容器和各种通用算法函数的中介,这样就不用为每种容器都专门写一个函数。
2.2.迭代器的种类
迭代器可以被分为5
种:输入迭代器、输出迭代器、前向迭代器、双向迭代器、随机访问迭代器。下面是它们的分类依据:
- 输入迭代器:只能单步向前迭代元素,不允许修改由该类迭代器引用的元素。
- 输出迭代器:只能单步向前迭代元素,对元素只有写的权力。
- 前向迭代器:拥有输入迭代器和输出迭代器的所有特性
- 双向迭代器:在前向迭代器的基础上提供了单步向后迭代元素的能力
- 随机访问迭代器:拥有上面4个迭代器的所有特性,而且可以像指针那样进行算术计算,而不是仅仅只有单步向前或向后迭代。
在STL
中,各容器提供的迭代器种类如下:
vector
,deque
:随机访问迭代器list
,set
,multiset
,map
,multimap
:双向迭代器stack
,queue
,priority_queue
:不支持任何迭代器
更加具体地分析,各种迭代器支持的操作如下:
- 所有迭代器:
p++
:后置单步向前迭代++p
:前置单步向前迭代
- 输入迭代器:
*p
:解引用作为右值(读)p=p1
:将一个迭代器赋给另一个迭代器p==p1
:比较迭代器的相等性p!=p1
:比较迭代器的不等性
- 输出迭代器:
*p
:解引用作为左值(写)p=p1
:将一个迭代器赋给另一个迭代器
- 前向迭代器:
- 输入迭代器和输出迭代器的所有支持操作的总和
- 双向迭代器:
p--
:后置单步向后迭代--p
:前置单步向后迭代
- 随机访问迭代器:
p+=i/p+i
:i步向前迭代p-=i/p-i
:i步向后迭代p[i]
:返回偏离i位元素的引用p<p1/p<=p1/p>p1/p>=p1
:比较两个迭代器的先后顺序位置
3.模板
3.1.什么是模板
所谓就是模板,就是编写类或者函数时先用一个具有适配功能的占位符
,在编译时编译器再对于各种具体类型再自动生成对应类型的类或者函数代码的功能。
3.2.模板的种类
在C++11
中,模板可以被分为4
种:函数模板、类模板、成员模板、别名模板。
3.2.1.函数模板
比较两个变量的大小:
template <class T>
T max(const T &x, const T &y)
{
return x < y ? y : x;
}
3.2.2.类模板
二维坐标系上的点:
template <class T>
class Point
{
private:
T x_;
T y_;
public:
Point(T x, T y) : x_(x), y_(y) {}
Point(const Point &other) : x_(other.x_), y_(other.y_) {}
//其他成员函数
};
3.2.3.成员模板
所谓成员模板就是任意类(不管是普通类还是模板类)中的模板类或者模板函数,即模板可以嵌套。比如为上面的二维点类增加一个get
成员函数:
template <class T>
class Point
{
private:
T x_;
T y_;
public:
Point(T x, T y) : x_(x), y_(y) {}
Point(const Point &other) : x_(other.x_), y_(other.y_) {}
//成员模板
template <class U> void get(U &dst_x, U &dst_y) const
{
dst_x = this->x_;
dst_y = this->y_;
}
};
3.2.4.别名模板
C++11
新引入的特性,其主要作用有两个:
①固定模板的某些待匹配参数从而产生一个更简单易用的新模板:
template< typename first, typename second, int third>
class SomeType;
template< typename second>
using TypedefName = SomeType<OtherType, second, 5>;
②更方便地声明函数指针的类型:
template< typename first, typename second, int third>
class SomeType;
template< typename second>
using TypedefName = SomeType<OtherType, second, 5>;
当然,你也可以把它当作typedef
来用
template <class T>
using Vec = std::vector<T>;
Vec<int> v;