Iterator definitions

An iterator is any object that, pointing to some element in a range of elements (such as an array or a container), has the ability to iterate through the elements of that range using a set of operators (with at least the increment (++) and dereference (*) operators).
The most obvious form of iterator is a pointer: A pointer can point to elements in an array, and can iterate through them using the increment operator (++). But other kinds of iterators are possible. For example, each container type (such as a list) has a specific iterator type designed to iterate through its elements.
Notice that while a pointer is a form of iterator, not all iterators have the same functionality of pointers; Depending on the properties supported by iterators, they are classified into five different categories:

Iterator categories

Iterators are classified into five categories depending on the functionality they implement:

Input and output iterators are the most limited types of iterators: they can perform sequential single-pass input or output operations.
Forward iterators have all the functionality of input iterators and -if they are not constant iterators- also the functionality of output iterators, although they are limited to one direction in which to iterate through a range (forward). All standard containers support at least forward iterator types.
Bidirectional iterators are like forward iterators but can also be iterated through backwards.
Random-access iterators implement all the functionality of bidirectional iterators, and also have the ability to access ranges non-sequentially: distant elements can be accessed directly by applying an offset value to an iterator without iterating through all the elements in between. These iterators have a similar functionality to standard pointers (pointers are iterators of this category).
The properties of each iterator category are:

category properties valid expressions
all categories copy-constructible, copy-assignable and destructible X b(a);
b = a;
Can be incremented ++a
a++
Random Access Bidirectional Forward Input Supports equality/inequality comparisons a == b
a != b
Can be dereferenced as an rvalue *a
a->m
Output Can be dereferenced as an lvalue
(only for mutable iterator types)
*a = t
*a++ = t
default-constructible X a;
X()
Multi-pass: neither dereferencing nor incrementing affects dereferenceability { b=a; *a++; *b; }
Can be decremented --a
a--
*a--
Supports arithmetic operators + and - a + n
n + a
a - n
a - b
Supports inequality comparisons (<, >, <= and >=) between iterators a < b
a > b
a <= b
a >= b
Supports compound assignment operations += and -= a += n
a -= n
Supports offset dereference operator ([]) a[n]

Where X is an iterator type, a and b are objects of this iterator type, t is an object of the type pointed by the iterator type, and n is an integer value.
For more details, see the references for input iterator, output iterator, forward iterator, bidirectional iterator and random-access iterator.

Functions


Iterator operations:

advance
Advance iterator (function template )
distance
Return distance between iterators (function template )
begin
Iterator to beginning (function template )
end
Iterator to end (function template )
prev
Get iterator to previous element (function template )
next
Get iterator to next element (function template )

Iterator generators:

back_inserter
Construct back insert iterator (function template )
front_inserter
Constructs front insert iterator (function template )
inserter
Construct insert iterator (function template )
make_move_iterator
Construct move iterator (function template )

Classes

iterator
Iterator base class (class template )
iterator_traits
Iterator traits (class template )

Predefined iterators

reverse_iterator
Reverse iterator (class template )
move_iterator
Move iterator (class template )
back_insert_iterator
Back insert iterator (class template )
front_insert_iterator
Front insert iterator (class template )
insert_iterator
Insert iterator (class template )
istream_iterator
Istream iterator (class template )
ostream_iterator
Ostream iterator (class template )
istreambuf_iterator
Input stream buffer iterator (class template )
ostreambuf_iterator
Output stream buffer iterator (class template )

Category tags

input_iterator_tag
Input iterator category (class )
output_iterator_tag
Output iterator category (class )
forward_iterator_tag
Forward iterator category (class )
bidirectional_iterator_tag
Bidirectional iterator category (class )
random_access_iterator_tag
Random-access iterator category (class )

C++设计模式——迭代器模式

Code不足之处:  直接将链表的创建和遍历都放在一类。

typedef struct tagNode
{
int value;
tagNode *pPre;
tagNode *pNext;
}Node; class CList
{
public:
CList();
CList(size_t n);
~CList(); bool PushBack(int value);
bool PopBack(int &value);
bool Insert(int pos, int value);
bool Delete(int pos);
bool IsEmpty();
int GetLength(); void Print(); // To iterate the list
bool HasNext();
int Next(); private:
int m_iLength;
Node *m_pCurrent;
Node *m_pHead;
Node *m_pTail;
};

迭代器模式

在GOF的《设计模式:可复用面向对象软件的基础》一书中对迭代器模式是这样说的:提供一种方法顺序访问一个聚合对象中各个元素,而又不需要暴露该对象的内部表示。

一个聚合对象,就是所谓的对象容器了;作为一个容器,都应该提供一种方法来让别人可以访问它的元素;但是,有的时候不希望遍历容器的人知道容器是如何实现的;那该怎么办?上面实现的链表,只提供了从头到尾的遍历,如果需要从尾到头的遍历呢?是不是又要添加对应的方法了呢!容器的遍历方式千变万化,不知道需求是如何的,如果需求变了,那么代码就会发生很大的改动。因此,必须去将一个容器的内部结构与它的遍历进行解耦。就好比STL中的容器,它将容器中对象的实现和遍历很好的解耦了,所以,无法知道它的内部是如何组织对象数据的,同时可以按照自己的想法去遍历容器,而不会出现任何差错。在项目中使用迭代器模式就能很好的将容器对象的内部表示与对它的遍历进行解耦。

Iterator:定义迭代器访问和遍历元素的接口;
ConcreteIterator:实现具体的迭代器;
Aggregate:定义的容器,创建相应迭代器对象的接口;
ConcreteAggregate:具体的容器实现创建相应迭代器的接口,该操作返回ConcreteIterator的一个适当的实例。

使用场合

  • 访问一个聚合对象的内容而无需暴露它的内部表示;
  • 支持对聚合对象的多种遍历(从前到后,从后到前);
  • 为遍历不同的聚合结构提供一个统一的接口,即支持多态迭代。
  • 作用

  • 它支持以不同的方式遍历一个聚合,甚至都可以自己定义迭代器的子类以支持新的遍历;
  • 迭代器简化了聚合的接口,有了迭代器的遍历接口,聚合本身就不再需要类似的遍历接口了。这样就简化了聚合的接口;
  • 在同一个聚合上可以有多个遍历,每个迭代器保持它自己的遍历状态;因此,我们可以同时进行多个遍历。
  • 代码实现

    #include <iostream>
    using namespace std; typedef struct tagNode
    {
    int value;
    tagNode *pNext;
    }Node; class JTList
    {
    public:
    JTList() : m_pHead(NULL), m_pTail(NULL){};
    JTList(const JTList &);
    ~JTList();
    JTList &operator=(const JTList &); long GetCount() const;
    Node *Get(const long index) const;
    Node *First() const;
    Node *Last() const;
    bool Includes(const int &) const; void Append(const int &);
    void Remove(Node *pNode);
    void RemoveAll(); private:
    Node *m_pHead;
    Node *m_pTail;
    long m_lCount;
    }; class Iterator
    {
    public:
    virtual void First() = 0;
    virtual void Next() = 0;
    virtual bool IsDone() const = 0;
    virtual Node *CurrentItem() const = 0;
    }; class JTListIterator : public Iterator
    {
    public:
    JTListIterator(JTList *pList) : m_pJTList(pList), m_pCurrent(NULL){} virtual void First();
    virtual void Next();
    virtual bool IsDone() const;
    virtual Node *CurrentItem() const; private:
    JTList *m_pJTList;
    Node *m_pCurrent;
    }; JTList::~JTList()
    {
    Node *pCurrent = m_pHead;
    Node *pNextNode = NULL;
    while (pCurrent)
    {
    pNextNode = pCurrent->pNext;
    delete pCurrent;
    pCurrent = pNextNode;
    }
    } long JTList::GetCount()const
    {
    return m_lCount;
    } Node *JTList::Get(const long index) const
    {
    // The min index is 0, max index is count - 1
    if (index > m_lCount - 1 || index < 0)
    {
    return NULL;
    } int iPosTemp = 0;
    Node *pNodeTemp = m_pHead;
    while (pNodeTemp)
    {
    if (index == iPosTemp++)
    {
    return pNodeTemp;
    }
    pNodeTemp = pNodeTemp->pNext;
    }
    return NULL;
    } Node *JTList::First() const
    {
    return m_pHead;
    } Node *JTList::Last() const
    {
    return m_pTail;
    } bool JTList::Includes(const int &value) const
    {
    Node *pNodeTemp = m_pHead;
    while (pNodeTemp)
    {
    if (value == pNodeTemp->value)
    {
    return true;
    }
    pNodeTemp = pNodeTemp->pNext;
    }
    return false;
    } void JTList::Append(const int &value)
    {
    // Create the new node
    Node *pInsertNode = new Node;
    pInsertNode->value = value;
    pInsertNode->pNext = NULL; // This list is empty
    if (m_pHead == NULL)
    {
    m_pHead = m_pTail = pInsertNode;
    }
    else
    {
    m_pTail->pNext = pInsertNode;
    m_pTail = pInsertNode;
    }
    ++m_lCount;
    } void JTList::Remove(Node *pNode)
    {
    if (pNode == NULL || m_pHead == NULL || m_pTail == NULL)
    {
    return;
    } if (pNode == m_pHead) // If the deleting node is head node
    {
    Node *pNewHead = m_pHead->pNext;
    m_pHead = pNewHead;
    }
    else
    {
    // To get the deleting node's previous node
    Node *pPreviousNode = NULL;
    Node *pCurrentNode = m_pHead;
    while (pCurrentNode)
    {
    pPreviousNode = pCurrentNode;
    pCurrentNode = pCurrentNode->pNext;
    if (pCurrentNode == pNode)
    {
    break;
    }
    } // To get the deleting node's next node
    Node *pNextNode = pNode->pNext; // If pNextNode is NULL, it means the deleting node is the tail node, we should change the m_pTail pointer
    if (pNextNode == NULL)
    {
    m_pTail = pPreviousNode;
    } // Relink the list
    pPreviousNode->pNext = pNextNode;
    } // Delete the node
    delete pNode;
    pNode = NULL;
    --m_lCount;
    } void JTList::RemoveAll()
    {
    delete this;
    } void JTListIterator::First()
    {
    m_pCurrent = m_pJTList->First();
    } void JTListIterator::Next()
    {
    m_pCurrent = m_pCurrent->pNext;
    } bool JTListIterator::IsDone() const
    {
    return m_pCurrent == m_pJTList->Last()->pNext;
    } Node *JTListIterator::CurrentItem() const
    {
    return m_pCurrent;
    } int main()
    {
    JTList *pJTList = new JTList;
    pJTList->Append(10);
    pJTList->Append(20);
    pJTList->Append(30);
    pJTList->Append(40);
    pJTList->Append(50);
    pJTList->Append(60);
    pJTList->Append(70);
    pJTList->Append(80);
    pJTList->Append(90);
    pJTList->Append(100); Iterator *pIterator = new JTListIterator(pJTList); // Print the list by JTListIterator
    for (pIterator->First(); !pIterator->IsDone(); pIterator->Next())
    {
    cout<<pIterator->CurrentItem()->value<<"->";
    }
    cout<<"NULL"<<endl; // Test for removing
    Node *pDeleteNode = NULL;
    for (pIterator->First(); !pIterator->IsDone(); pIterator->Next())
    {
    pDeleteNode = pIterator->CurrentItem();
    if (pDeleteNode->value == 100)
    {
    pJTList->Remove(pDeleteNode);
    break;
    }
    } // Print the list by JTListIterator
    for (pIterator->First(); !pIterator->IsDone(); pIterator->Next())
    {
    cout<<pIterator->CurrentItem()->value<<"->";
    }
    cout<<"NULL"<<endl; delete pIterator;
    delete pJTList; return 0;
    }

    代码中实现了一个单向链表,将链表与迭代器解耦。对于多态迭代,添加抽象类AbstractJTList,声明如下:

    class AbstractJTList
    {
    public:
    virtual Iterator *GetIterator() const = 0;
    };

    类JTList继承该抽象类,并实现GetIterator,如下:

    Iterator *JTList::GetIterator() const
    {
    return new JTListIterator(this);
    }

    好了,这样的话,在客户端就不用去new JTListIterator了,只需要这样:

    Iterator *pIterator = pJTList->GetIterator();

    这就完全好了;但是,这样又出现另外一个问题,在GetIterator中new了一个JTListIterator,对于客户端来说,并不知道这个new操作的存在,就会出现客户端不会去释放这个new开辟的内存,那么如何实现这个内存的自动释放呢。好了,就结合迭代器模式,再将之前总结的RAII机制再实际运用一次。根据RAII机制,需要将这个迭代器进行封装,让它具有自动释放的功能,就得借助另一个类,如下:

    class IteratorPtr
    {
    public:
    IteratorPtr(Iterator *pIterator) : m_pIterator(pIterator){}
    ~IteratorPtr() { delete m_pIterator; } Iterator *operator->(){ return m_pIterator; }
    Iterator &operator*() { return *m_pIterator; } private:
    IteratorPtr(const IteratorPtr &);
    IteratorPtr &operator=(const IteratorPtr &);
    void *operator new(size_t size);
    void operator delete(void *); private:
    Iterator *m_pIterator;
    };

    在使用的时候,就像下面这样,就省去了释放迭代器的麻烦了。

    IteratorPtr pIterator(pJTList->GetIterator());

    总结

    迭代器模式是一个很经典的模式。但是,就是因为它太经典了,如果每次都要程序员去重复造轮子,就有点说不过去了,所以,现在基本成型的类库,都非常好的实现了迭代器模式,在使用这些类库提供的容器时,并不需要我们亲自去实现对应的迭代器;就好比STL了。但是话又说回来了,如此经典的东西,你不去学习是不是很可惜啊;是吧,在当今社会,技多不压身。好了,永远记住,设计模式是一种思想,并不是一层不变的,一种思想,你懂的。

    iterator 及 迭代器模式(转发)的更多相关文章

    1. Iterator,迭代器模式,C++描述

      body, table{font-family: 微软雅黑; font-size: 13.5pt} table{border-collapse: collapse; border: solid gra ...

    2. 【设计模式 - 16】之迭代器模式(Iterator)

      1      模式简介 迭代器模式是JAVA中非常常用的模式,List.Map.Set等常见集合中都封装了迭代器Iterator. 迭代器模式的介绍: 迭代器模式用于顺序访问集合对象中的元素,而不需要 ...

    3. 迭代器模式和组合模式(head first设计模式——8)

      把迭代器模式和组合模式放在同一篇的原因是其联系比较紧密. 一.迭代器模式 1.1迭代器模式定义 迭代器模式提供一种方法顺序访问一个聚合对象中的各个元素,而不是暴露其内部的表示. 这个模式提供了一种方法 ...

    4. Java设计模式の迭代器模式

      迭代器模式定义 迭代器模式(Iterator),提供一种方法顺序访问一个聚合对象中的各种元素,而又不暴露该对象的内部表示. 迭代器模式的角色构成 (1)迭代器角色(Iterator):定义遍历元素所需 ...

    5. java设计模式之迭代器模式

      一.迭代器模式简介 迭代器模式提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示. 迭代器模式让我们能游走于聚合内的每一个元素,而又不暴露内部的表示.把游走的任务放在迭代器上,而不是 ...

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

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

    7. 迭代器模式/iterator模式/对象行为型模式

      意图 又名:游标(Cursor): 提供一种方法顺序访问一个聚合对象中各个元素,而又不暴露该对象的内部表示. 动机 一个聚合对象,提供访问元素的方法,而有不暴露它的内部结构.如list,将对列表的访问 ...

    8. C#设计模式系列:迭代器模式(Iterator)

      迭代器模式把对象的职责分离,职责分离可以最大限度减少彼此之间的耦合程度,从而建立一个松耦合的对象.职责分离的要点是对被分离的职责进行封装,并以抽象的方式建立彼此之间的关系. 1.迭代器模式简介 1.1 ...

    9. 迭代器模式(Iterator Pattern)

      迭代器模式(Iterator),提供一种方法顺序访问一个聚合对象中的各种元素,而又不暴露该对象的内部表示. 迭代器模式(Iterator)就是分离了聚合对象的遍历行为,抽象出一个迭代器来负责这样既可以 ...

    随机推荐

    1. Content is not allowed in prolog.解决方法

      将xml配置文件利用记事本另存为Anis编码的文件可以解决.

    2. 每日学习心得:Js基本数据类型常用方法扩展

      2014-02-17 前言: 节后的第一周上班,整个状态调整的还不错,已完全进入正常的工作状态.这一周主要还是对年前项目存在的一些问题进行完善.修整,基本上没有做大的改动.这里就把项目中经常用到的一些 ...

    3. Java 异步处理简单实践

      Java 异步处理简单实践 http://www.cnblogs.com/fangfan/p/4047932.html 同步与异步 通常同步意味着一个任务的某个处理过程会对多个线程在用串行化处理,而异 ...

    4. SQL 养成一个好习惯是一笔财富

      来源:MR_ke 链接:http://www.cnblogs.com/MR_ke/archive/2011/05/29/2062085.html 我们做软件开发的,大部分人都离不开跟数据库打交道,特别 ...

    5. Navicat(连接) -1之HTTP 设置

      HTTP 设置 HTTP 通道是一种连接到服务器的方法,使用与网络服务器相同的通讯协定(http://)和相同的端口(端口 80).这是当你的互联网服务供应商不允许直接连接,但允许创建 HTTP 连接 ...

    6. EF 自测例子

      public ActionResult Test()        { using (MvcShoppingContext db = new MvcShoppingContext())         ...

    7. express - ejs使用介绍

      http://blog.sina.com.cn/s/blog_ad0672d60101l2ml.html 1.express中使用ejs var express = require('express' ...

    8. java io流 创建文件、写入数据、设置输出位置

      java io流 创建文件 写入数据 改变system.out.print的输出位置 //创建文件 //写入数据 //改变system.out.print的输出位置 import java.io.*; ...

    9. (转)pdf文件结构

      PDF文件结构(一)  ————物理结构 PDF(Portable   Document   Format,便携式文档结构)是一种很有用的文件格式,其最大的特点是平台无关而且功能强大(支持文字/图象/ ...

    10. ubuntu14.04网络设置

      修改ip: /etc/network/interfaces