原地址:http://www.cnblogs.com/marchtea/archive/2012/02/27/2370068.html

前言:

  以下的内容为我阅读c++沉思录18,19,20章的笔记以及自己的想法.

正文:

  总所周知,c++的stl中提出了iterator的概念,这是C所没有的.在一般的使用中,iterator的行为很像c内建的指针.而在 java和c#中索性就直接取消了指针,而采用类似iterator的做法来代替了指针.很多编程人员在使用iterator的时候也仅仅把他当作了指针 的一个变体而没有多加注意.

  不过既然是学习,那我们在使用的时候也要知道其存在的原因,其分类以及用法吧.

  首先是问题的提出:

  很多人会觉得,既然C++沿用了C的指针这么强大的东西了,为什么还要iterator这么一群类来工作呢?

  我们知道,在我们编写模板的时候,对于使用了iterator做为参数的函数,往往该函数对于iterator有些特定的操作.比如下列2个函数

      

//在temple 中生命2个class 分别是calss P 和 class T
template<class P,class T>
P find(P start,P beyond,const T& x)  //函数find
{
while( start != beyond && * start != x)
++start;
return start;
} template<class P, class T>
void reverse(P start, P beyond)  //函数 reverse
{
while(start != beyond) {
--beyond;
if (start != beyond) {
T t = *start;
*start = *beyond;
*beyond = t;
++ start;
}
}
}

  我们可以看到,这两个函数都对模板参数P做了一定要求,在find中,我们要求P必须允许 != ,++和*(P)这三个运算符的操作,而对于reverse函数来说,其要求更多,运算符++,--,*(),!=都必须支持.问题就这么出来了,我们怎 么让所有人都遵守这一要求呢?或者说,后续采用这个模板的使用者怎么能在不知道实现细节的情况下了解并遵守这些要求呢?显然,我们需要一个分类方法来知道 如何界定不同种类的迭代器.

  不过这里还是没有解释一个疑惑,即这两个函数改成T的指针也能完成的很好,我们还要iterator做什么?

  答案很简单,不是所有数据结构都是线性的!对于一个链表来说,如果要实现上述的功能,我们必须重新写一个几乎一样仅仅是把++start变成 start = start->next的函数.显然,这样重复的事情我们是不希望碰到的,尤其如果函数还非常大的情况下.而这时候,iterator的作用就出来 了.对于链表,我们的链表的iterator(list_iterator)仅仅只要把operator++()重写成operator++(){now = now->next;},就能正常的使用find函数了.完全不需要重新编写.这就减少了我们算法的编写量.

  现在,既然我们知道了iterator的好处了之后,接下来我们就想知道之前提到的分类法是怎么回事了.经常听说输入迭代器,输出迭代器,前向迭代器,双向迭代器,随机存取迭代器是怎么回事.

  迭代器的分类:

  1.输入迭代器(input iterator)

        input iterator就像其名字所说的,工作的就像输入流一样.我们必须能

  • 取出其所指向的值  
  • 访问下一个元素
  • 判断是否到达了最后一个元素
  • 可以复制

  因此其支持的操作符有  *p,++p,p++,p!=q,p == q这五个.凡是支持这五个操作的类都可以称作是输入迭代器.当然指针是符合的.

  2.输出迭代器(output iterator)

    output iterator工作方式类似输出流,我们能对其指向的序列进行写操作,其与input iterator不相同的就是*p所返回的值允许修改,而不一定要读取,而input只允许读取,不允许修改.

    支持的操作和上头一样,支持的操作符也是 *p,++p,p++,p!=q,p == q.

 

  使用Input iterator和output iterator的例子:

 

 template<class In,class Out>
void copy(In start,In beyond, Out result)
{
while(start != beyond) {
*result = *start; //result是输出迭代器,其*result返回的值允许修改
++result;
++start;
}
} //简写
template<class In,class Out>
void copy(In start,In beyond, Out result)
{
while(start != beyond)
*result++ = *start++;//这个应该能看懂的...
}

   3.前向迭代器(forward iterator)

     前向迭代器就像是输入和输出迭代器的结合体,其*p既可以访问元素,也可以修改元素.因此支持的操作也是相同的.

   4.双向迭代器(bidirectional iterator)

     双向迭代器在前向迭代器上更近一步,其要求该种迭代器支持operator--,因此其支持的操作有  *p,++p,p++,p!=q,p == q,--p,p--

   5. 随机存取迭代器(random access iterator)

    即如其名字所显示的一样,其在双向迭代器的功能上,允许随机访问序列的任意值.显然,指针就是这样的一个迭代器.

    对于随机存取迭代器来说, 其要求高了很多:

  • 可以判断是否到结尾(  a==b or a != b)
  • 可以双向递增或递减( --a or ++a)
  • 可以比较大小( a < b or a > b or a>=b ...etc)
  • 支持算术运算( a + n)
  • 支持随机访问( a[n] )
  • 支持复合运算( a+= n)

  结构图:

  上面即为我们所讨论到的几个迭代器的层次.看起来很像继承是麽?

  但是实际上在STL中,这些并不是通过继承关联的.这些只不过是一些符合条件的集合.这样的好处是:少去了一个特殊的基类(input iterator),其次,使得内建类型指针可以成为iterator.

      其实只要明白iterator是满足某些特别的功能的集合(包括类和内建类型),就不会觉得是继承了.

   

  Iterator使用:

  一个ostream_iteartor的例子:

  

 #include <iostream>

 using namespace std;

 template<class T>
class Ostream_iterator {
public:
Ostream_iterator(ostream &os,const char* s):
strm(&os), str(s){}
Ostream_iterator& operator++() {return *this;}
Ostream_iterator& operator++(int) {return *this;}
Ostream_iterator& operator*() {return *this;}
Ostream_iterator& operator=(const T& t)
{
*strm << t << str;
return *this;
} private:
ostream* strm;
const char *str;
}; template<class In,class Out>
Out Copy(In start,In beyond,Out dest)
{
while(start != beyond)
*dest++ = *start++;
return dest;
} int main()
{
Ostream_iterator<int> oi(cout, " \n"); int a[];
for (int i = ;i!=;++i)
a[i] = i+;
Copy(a,a+,oi); return ;
}

  在这个例子中,我们简单的构造了一个ostream_iterator,并且使用了copy来输出..这个ostream_iterator和STL差别还是很大,不过功能上已经差不多了.我想读者们应该也能看懂代码吧,所以就不用多做什么解释了.
   第二个例子中,我们讲构造一个istream_iterator.

  对于一个istream_iterator来说,我们必须要存的是T buffer和istream *strm.不过由于istream的特殊性,我们必须知道buffer是否满,以及是否到达尾部,因此,我们的结构是这样的 

 

 template <class T>
class Istream_Iterator{ private:
istream *strm;
T buffer;
int full;
int eof;
};

  对于构造函数来说,因为有eof的存在,因此,我们自然想到,我们的默认构造函数就应该把eof设为1.而对于有istream的iterator,都应该为0.

  

 Istream_iterator(istream &is):
strm(&is),full(),eof(){}
Istream_iterator():strm(),full(),eof(){}

  对于我们的版本的istream_iterator来说,我们需要完成的功能有

  • 进行取值操作(dereference),既*(p)
  • 自增操作
  • 比较

  自增操作:

  我们知道,在istream中,一旦获取到一个值了之后,我们将不在访问这个值.我们的iterator也要符合这样的要求,因此,我们通过full来控制.

 

     Istream_iterator& operator++(){
full = ;
return *this;
}
Istream_iterator operator++(int){
Istream_iterator r = *this;
full = ;
return r;
}

  Dereference:

  对于解除引用操作来说,我们需要将流中缓存的值存入buffer内.同时,我们要判断读取是否到结尾,到了结尾则应当出错.

  在这里我们写了一个私有函数fill(),这个将在比较的时候用到

  

 T operator*() {
fill();
assert(eof);//我们断定不应该出现eof
return buffer;
}
void fill(){
if (!full && !eof) {
if (*strm >> buffer)
full = ;
else
eof = ;
}
}

  比较:

  对于比较来说,只有两个istream_iterator都同一个对象或者都处于文件尾时,这两个istream_iterator才相等.因此这里其比较对象为istream_iterator而不是const istream_iterator

template<class T>
int operator==(Istream_iterator<T> &p,Istream_iterator<T>& q)
{
if (p.eof && q.eof)
return ;
if (!p.eof && !q.eof)
return &p == &q;
p.fill();q.fill();
return p.eof == q.eof;
}

最后的测试例子,读者可以把之前的copy和ostream_iterator拷下来

int main()
{
Ostream_iterator<int> o(cout,"\t");
Istream_iterator<int> i(cin);
Istream_iterator<int> eof; Copy(i,eof,o);
return ;
}

结论:

  iterator是STL实现所有算法已经其通用型的基础.通过对iterator分类,使得算法的使用者在使用时不需要知道具体实现就可知道算法对于参数的要求,形成一个通用的体系.

(转) c++ 迭代器的更多相关文章

  1. 匹夫细说C#:庖丁解牛迭代器,那些藏在幕后的秘密

    0x00 前言 在匹夫的上一篇文章<匹夫细说C#:不是“栈类型”的值类型,从生命周期聊存储位置>的最后,匹夫以总结和后记的方式涉及到一部分迭代器的知识.但是觉得还是不够过瘾,很多需要说清楚 ...

  2. 轻量级“集合”迭代器-Generator

    Generator是PHP 5.5加入的新语言特性.但是,它似乎并没有被很多PHP开发者广泛采用.因此,在我们了解PHP 7对Generator的改进之前,我们先通过一个简单却显而易见的例子来了解下G ...

  3. C#设计模式-迭代器模式

    一. 迭代器(Iterator)模式 迭代器是针对集合对象而生的,对于集合对象而言,必然涉及到集合元素的添加删除操作,同时也肯定支持遍历集合元素的操作,我们此时可以把遍历操作也放在集合对象中,但这样的 ...

  4. 设计模式(十):从电影院中认识"迭代器模式"(Iterator Pattern)

    上篇博客我们从醋溜土豆丝与清炒苦瓜中认识了“模板方法模式”,那么在今天这篇博客中我们要从电影院中来认识"迭代器模式"(Iterator Pattern).“迭代器模式”顾名思义就是 ...

  5. Python(四)装饰器、迭代器&生成器、re正则表达式、字符串格式化

    本章内容: 装饰器 迭代器 & 生成器 re 正则表达式 字符串格式化 装饰器 装饰器是一个很著名的设计模式,经常被用于有切面需求的场景,较为经典的有插入日志.性能测试.事务处理等.装饰器是解 ...

  6. 用struts2标签如何从数据库获取数据并在查询页面显示。最近做一个小项目,需要用到struts2标签从数据库查询数据,并且用迭代器iterator标签在查询页面显示,可是一开始,怎么也获取不到数据,想了许久,最后发现,是自己少定义了一个变量,也就是var变量。

    最近做一个小项目,需要用到struts2标签从数据库查询数据,并且用迭代器iterator标签在查询页面显示,可是一开始,怎么也获取不到数据,想了许久,最后发现,是自己少定义了一个变量,也就是var变 ...

  7. Java迭代器

    迭代器在其实就是指针,读取集合或者数组中的一个值,读完以后又指向下一条数据. iterator() 迭代器只读,不能改效率要比for循环高 迭代器的一些方法: HasNext() 如果仍有元素可以迭代 ...

  8. Python 生成器与迭代器 yield 案例分析

    前几天刚开始看 Python ,后因为项目突然到来,导致Python的学习搁置了几天.然后今天看回Python 发现 Yield 这个忽然想不起是干嘛用的了(所以,好记性不如烂笔头.).然后只能 花点 ...

  9. 设计模式02迭代器(java)

    先贴代码,有空来写内容. 1.定义集合 import java.util.List; import java.util.ArrayList; //coollection是我自己定义的一个集合,因为要写 ...

  10. JAVA编程思想(第四版)学习笔记----11.5 List,11.6迭代器

    Collection类的层次结构图(来源与网络)如下所示: 接口:Iterator<T> public interface Iterable<T> Iterable<T& ...

随机推荐

  1. 什么是JSONP以及它是怎么产生的

    什么是JSONP以及它是怎么产生的         1.什么是jsonp                 JSONP(JSON with Padding)是一个非官方的协议,它允许在服务器端集成Scr ...

  2. jQuery选择器的学习

    jQuery的核心在于它的选择器,通过观看视频和阅读,发现jQuery选择器大体上的分类可分为这么几种(不同人方式不同,这里选择一个自认为比较好的): 1.基础选择器(对应api文档中的基本选择器和层 ...

  3. Python一路走来 面向对象1

    面向对象: 类,对象 函数放在类里,叫方法 封装 #如何调用 1. 创建对象, 类名() obj= Foo() 2. 通过对象去执行方法 obj.mail("leon@me.com" ...

  4. Yoga安装Ubuntu后,wifi和亮度调节问题

    http://askubuntu.com/questions/318608/lenovo-yoga-13-realtek-wireless-driver/358479#358479 http://it ...

  5. gridview两列数据的互换

    如下图所示: GridView绑定数据的时候,若ReName列里面有数据,则显示ReName列里面的数据,如果没有数据,则显示Name列里面的数据.Name和ReName是数据表里面的两个字段< ...

  6. 25045操作标准子程序集41.C

    /* ;程 序 最 后 修 改 时 间 0-4-3 23:43 ;软 件 标 题:25045操作标准子程序集41 ;软 件 说 明:25045 I2C 串行EEPROM 驱动 ;___________ ...

  7. XPath <第四篇>

    .Net框架下的System.Xml.XPath命名空间提供了一系列的类,允许你应用XPath数据模式查询和展示XML文档数据. 一.XPath介绍 XPath有七种类型的节点:元素.属性.文本.命名 ...

  8. 【转】Device Tree(三):代码分析

    原文网址:http://www.wowotech.net/linux_kenrel/dt-code-analysis.html 一.前言 Device Tree总共有三篇,分别是: 1.为何要引入De ...

  9. bzoj1751 [Usaco2005 qua]Lake Counting

    1751: [Usaco2005 qua]Lake Counting Time Limit: 5 Sec  Memory Limit: 64 MB Submit: 168  Solved: 130 [ ...

  10. asp.net mvc4中自定义404

    原文地址:http://www.chuchur.com/asp-net-mvc4-404/ 定义404 方法当然有很多种.不同的方法所展现的形式也不一样,用户所体验也不一样.以下提供2两种 方法一: ...