一.iterator_traits(迭代器萃取机) #include <iterator>
template <class Iterator>
struct iterator_traits
{
typedef typename Iterator::difference_type differebce_type;
typedef typename Iterator::value_type value_type;
typedef typename Iterator::reference reference;
typedef typename Iterator::iterator_category iterator_category;
}
假如我们定义了一个迭代器MyIterator
- difference_type:两个MyIterator类型的迭代器之间差别值的类型
- value_type:MyIterator类型的迭代器所指向值的类型
- pointer:MyIterator类型的迭代器所表示的指针类型
- reference:来自*MyIterator的引用类型
- iterator_category:迭代器类别的标签类型:input_iterator_lag. output_iterator_tag. forward_iterator_tag. bidirectional_iterator_tag. random_access_iterator_tag
一个满足STL要求的迭代器必须全部定义这些别名
template <typename Iter>
void my_swap(Iter a, Iter b)
{
typename std::iterator_traits<Iter>::value_type tmp = *a;
value_type tmp = *a;
*a = *b;
*b = tmp;
}
当函数 以一个迭代器为参数时,会出现这样一个尴尬,tmp的类型是什么呢?显然tmp是迭代器Iter所指向元素值的类型,但当一个迭代器实例化前,迭代器自己都不知道自己指向元素的类型,那么怎么告知编译器tmp的类型呢?一种方法是typename MyIterator::value_type tmp = *a;
这样就必须知道iter是MyIterator还是其他什么迭代器,有点麻烦。iterator_traits模板就来帮忙了,通过这样的表述“typename std::iterator_traits::value_type tmp”,编译器明白了tmp的类型就是Iter指向的元素的类型。这样当实例化一个类时,就可以实例化他的迭代器了, 然后可以实例化iterator_traits模板,最后tmp的类型确定了。
iterator_traits模板是面向编译器的,方便编译器编译,但本身不会变成可执行程序。
当迭代器变成指针(当指向const对象时,也需要进行局部特化处理)时,iterator_traits模板特例化为
template <class T>
struct iterator_traits<T*>
{
typedef ptrdiff_t difference_type;
typedef T value_type;
typedef T* value_type;
typedef T& reference;
typedef random_access_iterator_tag iterator_category;
};
二.迭代器模板
template <class Category, class T, class Difference = ptrdiff_t, class Pointer = T*, class Rerence = T&>
struct iterator
{
typedef T value_type;
typedef Difference difference_type;
typedef Pointer pointer;
typedef Reference reference;
typedef Category iterator_category;
};
以迭代器,模板为基类来定义迭代器类
class My_Iterator:public std::iterator<std::random_access_iterator_tag, int>
{
//members of the iterator class..
}
这样迭代器模板就成功将迭代器与iterator_traits模板联系起来。
总结:以上迭代器模板与iterator_traits模板是告诉我们,STL对迭代器做了一些标准规定,这方便了我们建一个迭代器,我
们只要遵守即可,却不是编程时的主要点。
三.STL迭代器成员函数
1.Iterator(); Iterator (const Iterator& y); ~Iterator (); Iterator & operator = (const Iterator & y);
这些是所有迭代器都需要的。
2.其他一些运算符成员函数==, !=, >, <, >=, <=等,及其他我们可以依据具体的类和具体需要来实现的成员函数。
四.具体实现迭代器
迭代器与其容器类之间的交互形式
1.迭代器不能 访问容器类中的私有成员变量,只能靠容器提供的接口来实现迭代器的功能
迭代器中的主要成员:变量:其指向的容器指针,存储容器中元素位置的变量
成员函数:以容器为参数的构造函数(将迭代器指向容器),以及其他重载的运算符函数(改
变存储元素为位置的变量的值并调用容器接口得到容器中指定元素的值)。
容器中的主要成员:成员函数:提供接口(以元素位置为参数,返回元素值),生成指向本容器的迭代器
注:当迭代器是以指针存储容器元素位置时,就无需调用容器相应接口,而容器也无需提供此类接口
2.迭代器和容器互为友元类,这样成员变量的访问不再是问题
#include <iostream>
#include <iterator>
using namespace std;
template <class T>
class iter:public iterator<input_iterator_tag,T>
{
public:
iter(T * pp):p(pp){}
iter(const iter<T> &i):p(i.p){}
iter<T> & operator = (const iter<T>& i){p = i.p; return *this;}
T & operator *(){return *p;}
T & operator ++(){return *(++p);}//前置++
private:
T * p;
};
template <class T>
class aggregate
{
public:
typedef iter<T> iter; //这句话要申明为public ,否则在main()中就不能用aggregate<int>::iter了;这句话将iter与
//aggregate<T>联系起来了,感觉这与iterator_traits和struct iterator原理一样
aggregate(T *d = NULL,int len = 0):data(d),length(len){}
~aggregate(){}
iter begin();
iter end();
private:
T *data;
int length;
};
template <class T>
typename aggregate<T>::iter aggregate<T>::begin() //前面要加typename 否则编译器会将iter看成是aggregate<T>的成员
{
iter a(data);
return a;
}
template <class T>
typename aggregate<T>::iter aggregate<T>:: end()
{
iter b(data + length);
return b;
}
int main()
{
int d[10] = {1, 3, 2, 5, 4, 8, 9, 8, 7, 0};
aggregate<int> a(d);
aggregate<int>::iter b = a.begin();
++b;
cout << *b << endl;
return 0;
}