所谓泛型编程,就是不依赖于某一具体类型而使代码具有很强适应性的编程范式。我们看下面的求和函数是如何一步步进化成最纯粹的泛型编程的。
最开始,sum
函数是这样子的:
double sum(const std::vector &vec) {
double result = 0.0;
for(const auto e : vec) {
result += e;
}
return result;
}
显然这个函数只适用于std::vector
类型的容器变量,现在我们可以把vector
内部元素抽象成一个模板,正如下面这样的:
template
T sum(const std::vector &vec, T start) {
for(const auto e : vec) {
start += e;
}
return start;
}
但是函数仍然只适用于std::vector
类型的容器变量,如果想要兼容std::list
等等的其他容器,可以引入迭代器,进一步抽象。
template
T sum(InputIterator first, InputIterator last, T start) {
while(first != last) {
start += *first++;
}
return start;
}
这样我们分3
步完成了求和函数的泛型编程,正如你在上面看到的那样,要实现泛型编程,必须理解两个很重要的概念才行——模板
和迭代器
。
迭代器非常类似于指针,用于访问容器中的各元素,而STL
中的迭代器,常作为容器和各种通用算法函数的中介,这样就不用为每种容器都专门写一个函数。
迭代器可以被分为5
种:输入迭代器、输出迭代器、前向迭代器、双向迭代器、随机访问迭代器。下面是它们的分类依据:
在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位元素的引用pp1/p>=p1
:比较两个迭代器的先后顺序位置所谓就是模板,就是编写类或者函数时先用一个具有适配功能的占位符
,在编译时编译器再对于各种具体类型再自动生成对应类型的类或者函数代码的功能。
在C++11
中,模板可以被分为4
种:函数模板、类模板、成员模板、别名模板。
比较两个变量的大小:
template
T max(const T &x, const T &y)
{
return x < y ? y : x;
}
二维坐标系上的点:
template
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_) {}
//其他成员函数
};
所谓成员模板就是任意类(不管是普通类还是模板类)中的模板类或者模板函数,即模板可以嵌套。比如为上面的二维点类增加一个get
成员函数:
template
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 void get(U &dst_x, U &dst_y) const
{
dst_x = this->x_;
dst_y = this->y_;
}
};
C++11
新引入的特性,其主要作用有两个:
①固定模板的某些待匹配参数从而产生一个更简单易用的新模板:
template< typename first, typename second, int third>
class SomeType;
template< typename second>
using TypedefName = SomeType;
②更方便地声明函数指针的类型:
template< typename first, typename second, int third>
class SomeType;
template< typename second>
using TypedefName = SomeType;
当然,你也可以把它当作typedef
来用
template
using Vec = std::vector;
Vec v;