提供一种方法,使之能够依序巡访某个聚合物(容器)所含的各个元素,而又无需暴露容器的内部表述方式。stl的中心思想就是容器和算法分离,然后用一个胶着剂将它们撮合在一起。下面展示一下应用:比如算法find(),要寻找各种容器里的数据,代码如下:
void test_find(){
const int arraySize = 10;
int num[arraySize] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
vector <int> vec(num, num + arraySize);
vector <int> ::iterator it1 = find(vec.begin(), vec.end(), 8);
if (it1 == vec.end()){
cout << "not found" << endl;
}else{
cout << "found it :" << *it1 << endl;
}
list <int> lis(num, num + arraySize);
list <int>::iterator it2 = find (lis.begin(), lis.end(), 4);
if (it1 == vec.end()){
cout << "not found" << endl;
}else{
cout << "found it :" << *it2 << endl;
}
deque <int> deq(num, num + arraySize);
deque <int>::iterator it3 = find (deq.begin(), deq.end(), 5);
if (it3 == deq.end()){
cout << "not found" << endl;
}else{
cout << "found it :" << *it3 << endl;
}
}
从上面的代码可以看出,只要给出不同的迭代器,find()就会对不同的容器进行查找操作。
迭代器是一种类似于指针的对象,而又不同于普通的原生指针,它能够让各种对象看上去像指针一样操作,,不仅仅是基本类型;众所周知,指针最常用的操作就是取值和成员访问:也就是说迭代器作为一种智能指针,需要对operator*和operator->进行重载工作,这里放一段标准库里的auto_ptr的程序,可以更好的理解智能指针:
template <class T>
class auto_ptr{
public:
explicit auto_ptr(T *p = 0) : pointee(p){} //普通构造函数
template <class U>
auto_ptr(auto_ptr<U>& rhs) : pointee(rhs){} //拷贝构造
template <class U>
auto_ptr& operator= (auto_ptr<U>& rhs){
if (this != &rhs) reset(rhs.release);
return *this;
}
~auto_ptr() {delete pointee;}
//最关键的两个
T& operator*() const {return *pointee;}
T* operator->() const {return pointee;}
private:
T* pointee;
};
//调用
auto_ptr<string> ps (new string("ss"));
cout << *ps << endl; //输出ss;
//string可以换成自己的自定义类;
因此完全可以自己按照auto_ptr写一个迭代器,再加上自己需要的功能,比如指针自增(重载operator++)等,比如:
ListIter <ListItem<int>> begin(mylist.front());
//ListIter是迭代器类,,ListItem<int>是一个单向链表类,mylist是直接定义的一个基于单链表的容器
//这样说明,begin就是指向自定义容器第一个位置的指针,是不是类似于:vector<int>::iterator ite = vec.begin();
既然迭代器要把两个独立的部件算法和容器撮合在一起,那么相应的类别必须得一样;当然,编译器是自带参数推导的,就比如函数模板,它是会自己推导出传递的是什么类型,但是返回值没办法推导呀,这个也可以解决,使用内嵌声明就行了:
template <class T>
struct MyIter{
typedef T value_type; 内嵌类型
T* ptr;
MyIter(T* p = 0): ptr(p){}
T& operator*()const {return *ptr;}
};
template <class I>
typename I::value_type //这一行都是func的返回类型(因为I是一个template参数,在编译器具现之前,编译器对I一无所知,使用typename可以告诉编译器这是一个类型
func(I ite){
return *ite;
}
但是指针不能内嵌类型,如果迭代器是一个原生指针不就无法内嵌吗?这里就不得不说一个模板偏特化了。
模板偏特化分为两种:一种是个数上的特化,一种是类型上的特化:
//个数上的特化
//比如泛化模板如:
template<class T, class U, class V>//这是一种泛化
//个数上的特化就是让一个值有默认值,比如:
template<class T, class U, class V == string>
//类型上的特化
//比如一个模板
template <class T>
class Demo <T*>{}//这就是类型上的特化,只接受原生指针;
回到之前的问题;算法和容器两个独立的部件靠迭代器撮合一起的,那必须对应的类型要一样,就好比是这样一个场景:算法问迭代器,你作为我算法的参数,你指向的对象的数据类型是什么,到时候返回值别错了。你知道吗? 迭代器如果说不知道,,那就类型不对就无法进行下去了,如果说知道,那算法就直接说,那好,我要对你指向的容器进行操作了,这样操作自然而然的就通顺了,,那迭代器是怎么回答算法这个问题的呢?这就得看看萃取机了。
这里就直接把对应的代码贴出来
// 用于traits出迭代其所指对象的型别
template <class Iterator>那
struct iterator_traits
{
// 迭代器类型, STL提供五种迭代器
typedef typename Iterator::iterator_category iterator_category;
// 迭代器所指对象的型别
// 如果想与STL算法兼容, 那么在类内需要提供value_type定义
typedef typename Iterator::value_type value_type;
// 这个是用于处理两个迭代器间距离的类型
typedef typename Iterator::difference_type difference_type;
// 直接指向对象的原生指针类型
typedef typename Iterator::pointer pointer;
// 这个是对象的引用类型
typedef typename Iterator::reference reference;
};
// 针对指针提供特化版本
template <class T>
struct iterator_traits<T*>
{
typedef random_access_iterator_tag iterator_category;
typedef T value_type;
typedef ptrdiff_t difference_type;
typedef T* pointer;
typedef T& reference;
};
// 针对指向常对象的指针提供特化
template <class T>
struct iterator_traits<const T*>
{
typedef random_access_iterator_tag iterator_category;
typedef T value_type;
typedef ptrdiff_t difference_type;
typedef const T* pointer;
typedef const T& reference;
};
那萃取机怎么告诉迭代器有没有这个类型呢?
这里直接来个代码比较好理解:
template <class T, class V>
typename iterator_traits<I>::difference_type //返回值
count(T first, I last, const T& value){
//统计容器里value的个数
typename iterator_traits<I>::difference_type n = 0;
//这里就是回答,因为迭代器I可以通过萃取机萃取出需要的difference_type,如果通过::出不来类型,那就是回答不了。
...
return n;
}
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。