C++泛型编程入门

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种:输入迭代器、输出迭代器、前向迭代器、双向迭代器、随机访问迭代器。下面是它们的分类依据:

  1. 输入迭代器:只能单步向前迭代元素,不允许修改由该类迭代器引用的元素。
  2. 输出迭代器:只能单步向前迭代元素,对元素只有写的权力。
  3. 前向迭代器:拥有输入迭代器和输出迭代器的所有特性
  4. 双向迭代器:在前向迭代器的基础上提供了单步向后迭代元素的能力
  5. 随机访问迭代器:拥有上面4个迭代器的所有特性,而且可以像指针那样进行算术计算,而不是仅仅只有单步向前或向后迭代。

STL中,各容器提供的迭代器种类如下:

  1. vectordeque:随机访问迭代器
  2. listsetmultisetmapmultimap:双向迭代器
  3. stackqueuepriority_queue:不支持任何迭代器

更加具体地分析,各种迭代器支持的操作如下:

  1. 所有迭代器:
    • p++:后置单步向前迭代
    • ++p:前置单步向前迭代
  2. 输入迭代器:
    • *p:解引用作为右值(读)
    • p=p1:将一个迭代器赋给另一个迭代器
    • p==p1:比较迭代器的相等性
    • p!=p1:比较迭代器的不等性
  3. 输出迭代器:
    • *p:解引用作为左值(写)
    • p=p1:将一个迭代器赋给另一个迭代器
  4. 前向迭代器:
    • 输入迭代器和输出迭代器的所有支持操作的总和
  5. 双向迭代器:
    • p--:后置单步向后迭代
    • --p:前置单步向后迭代
  6. 随机访问迭代器:
    • 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;
  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值