STL配接器

配接器(Adapter)在 STL 组件的灵活组合运用功能上,扮演着轴承、转换器的角色,即将一个 class 的接口转换为另一个 class 的接口,使原本因接口不兼容而不能合作的 classes,可以一起运作,它事实上是一种设计模式

STL 主要提供如下三种配接器:

(1)改变仿函数(functors)接口,称之为 function adapter

(2)改变容器(containers)接口,称之位 container adapter

(3)改变迭代器(iterators)接口者,称之为 iterator adapter

1. container adapter

STL 提供的两个容器 queue 和 stack,其实都不过是一种配接器,是对 deque (双端队列)接口的修饰而成就自己的容器风貌。queue 和 stack 底层都是由 deque 构成的,它们封住所有 deque 对外接口,只开发符合对应原则的几个函数,故它们是适配器,是一个作用于容器之上的适配器。

2. iterator adapter.

STL 提供了许多应用于迭代器身上的配接器,包括 insert iterators,reverse iterators,iostream iterators

  • insert iterators 可以将一般迭代器的赋值操作转变为插入操作。此迭代器包括专门从尾端插入操作 back_insert_iterator,专门从头端插入操作 front_insert_iterator,以及可从任何位置执行插入操作的 insert_iterator。因 iterator adapters 使用接口不是十分直观,STL 提供三个相应的函数 back_inserter ()、front_inserter ()、inserter (),从而提高使用时的便利性。

  • reverse iterators 可以将一般迭代器的行进方向逆转使原本应该前进的 operator++ 变成了后退操作,使原本应该后退的 operator–变成了前进操作。此操作用在 “从尾端开始进行” 的算法上,有很大的方便性。

  • iostream iterators 可以将迭代器绑定到某个 iostream 对象身上。绑定到 istream 对象身上,为 istream_iterator,拥有输入功能绑定到 ostream 对象身上,成为 ostream_iterator,拥有输出功能。此迭代器用在屏幕输出上,非常方便。

.1. reverse iterators

template <class Iterator>
class reverse_iterator
{
protected:
  Iterator current;
public:
  // 反向迭代器的5种相应型别和正向的正向迭代器相同
  typedef typename iterator_traits<Iterator>::iterator_category iterator_category;
  typedef typename iterator_traits<Iterator>::value_type value_type;
  typedef typename iterator_traits<Iterator>::difference_type difference_type;
  typedef typename iterator_traits<Iterator>::pointer pointer;
  typedef typename iterator_traits<Iterator>::reference reference;

  // 正向迭代器
  typedef Iterator iterator_type;
  // 反向迭代器
  typedef reverse_iterator<Iterator> self;

public:
  // 构造函数
  reverse_iterator() {}
  // 将反向迭代器与某种迭代器联系起来
  explicit reverse_iterator(iterator_type x) : current(x) {}
  reverse_iterator(const self& x) : current(x.current) {}

  // 返回正向迭代器      
  iterator_type base() const { return current; }
  // 反向迭代器取值时,先将正向迭代器后退一位,再取值
  reference operator*() const {
    Iterator tmp = current;
    return *--tmp;
  }
  // 反转后end变成了begin. begin变成了end
  // 注意一点就是end是指向最后一个元素的后一个位置
  self& operator++() {
    --current;
    return *this;
  }
  self operator++(int) {
    self tmp = *this;
    --current;
    return tmp;
  }
  self& operator--() {
    ++current;
    return *this;
  }
  self operator--(int) {
    self tmp = *this;
    ++current;
    return tmp;
  }

  // 前进和后退方向相反
  self operator+(difference_type n) const {
    return self(current - n);
  }
  self& operator+=(difference_type n) {
    current -= n;
    return *this;
  }
  self operator-(difference_type n) const {
    return self(current + n);
  }
  self& operator-=(difference_type n) {
    current += n;
    return *this;
  }
  reference operator[](difference_type n) const { return *(*this + n); }  
};

3. functor adapter

functor adapters 是所有配接器中数量最庞大的一个族群,其配接灵活度是后两者不能及的,可以配接、配接、再配接。其中配接操作包括系结(bind)、否定(negate)、组合(compose)、以及对一般函数或成员函数的修饰(使其成为一个仿函数)。它的价值在于,通过它们之间的绑定、组合、修饰能力,几乎可以无限制地创造出各种可能的表达式(expression),搭配 STL 算法一起演出

由于仿函数就是 “将 function call 操作符重载” 的一种 class,而任何算法接受一个仿函数时,总是在其演算过程中调用该仿函数的 operator (),这使得不具备仿函数之形、却有真函数之实的 “一般函数” 和 “成员函数(member functions)感到为难。如果” 一般函数 “和 “成员函数” 不能纳入复用的体系中,则 STL 的规划将崩落了一角。为此,STL 提供了为数众多的配接器,使 “一般函数” 和 “成员函数” 得以无缝地与其他配接器或算法结合起来。

所有期望获取配接能力的组件,本身都必须是可配接的,即一元仿函数必须继承自 unary_function,二元仿函数必须继承自 binary_function,成员函数必须以 mem_fun 处理过,一般函数必须以 ptr_fun 处理过。一个未经 ptr_fun 处理过的一般函数,虽然也可以函数指针的形式传给 STL 算法使用,却无法拥有任何配接能力

// 以下配接器其实就是把一个一元函数指针包起来;
// 当仿函数被使用时,就调用该函数指针
template <class _Arg, class _Result>
class pointer_to_unary_function : public unary_function<_Arg, _Result> 
{
protected:
  _Result (*_M_ptr)(_Arg);     // 内部成员,一个函数指针
public:
  pointer_to_unary_function() {}
  // 以下constructor将函数指针记录于内部成员之中
  explicit pointer_to_unary_function(_Result (*__x)(_Arg)) : _M_ptr(__x) {}
  // 通过函数指针执行函数
  _Result operator()(_Arg __x) const { return _M_ptr(__x); }
};

// 辅助函数,使我们能够方便运用pointer_to_unary_function
template <class _Arg, class _Result>
inline pointer_to_unary_function<_Arg, _Result> ptr_fun(_Result (*__x)(_Arg))
{
  return pointer_to_unary_function<_Arg, _Result>(__x);
}

Resource

0%