/
// Iterator
// - Provide a way to access the elements of an aggregate object sequentially without
// exposing its underlying representation.
//
// Author : ZAsia
// Date : 15/05/14
// Warning : In practice, declaration and implementation should
// be separated(.h and .cpp).
/
#include
using namespace std;
#define DEFAULT_CAPACITY 128
// Iterator
// - defines an interface for accessing and traversing elements.
template
class Iterator
{
public:
virtual void First() = 0;
virtual void Next() = 0;
virtual bool IsDone() const = 0;
virtual Item CurrentItem() const = 0;
};
// forward declaration
template
class ConcreteAggregate;
// ConcreteIterator
// - implements the Iterator interface.
// - keep the track of the current position in the traversal of the aggregate.
//
// - the implementation of ReverseIterator is identical, except its First operation
// positions _current to the end of the ConcreteAggregate, and Next decrements
// _current toward the first item.
template
class ConcreteIterator : public Iterator
{ public: ConcreteIterator(const ConcreteAggregate
*aggr) : _aggr(aggr), _current(0) { } // First positions the iterator to the first element. virtual void First() { _current = 0; } // Next advances the current element. virtual void Next() { if (_current < _aggr->Count()) { ++_current; } } // IsDone checks whether the index refers to an element within the List. virtual bool IsDone() const { return _current >= _aggr->Count(); } // CurrentItem returns the item at the current index. // If the iteration has already terminated, then throw an exception. virtual Item CurrentItem() const { if (IsDone()) { cout << "Iterator out of bounds." << endl; return 0; } return _aggr->Get(_current); } private: const ConcreteAggregate
*_aggr; long _current; }; // Aggregate // - defines an interface for creating an Iterator object. template
class Aggregate { public: Aggregate( ) { } virtual ~Aggregate() { } virtual ConcreteIterator
*CreateIterator() = 0; virtual void Append(Item item) = 0; virtual void Remove(Item item) = 0; virtual long Count() const = 0; virtual Item Get(long index) const = 0; }; // ConcreteAggregate // - implements the Iterator creation interface to return an instance of the // proper ConcreteIterator. template
class ConcreteAggregate : public Aggregate
{ public: ConcreteAggregate() : _size(0), _iter(nullptr) { } virtual ConcreteIterator
*CreateIterator() { if (_iter) { return _iter; } return new ConcreteIterator
(this); } virtual void Append(Item item) { if (_size > DEFAULT_CAPACITY) { cout << "Aggregate out of capacity." << endl; return; } _arr[_size++] = item; } virtual void Remove(Item item) { if (_size == 0) { return; } for (int i = 0; i < _size; ++i) { if (_arr[i] == item) { for (int j = i; j < _size - 1; ++j) { _arr[j] = _arr[j + 1]; } --_size; } } } virtual long Count() const { return _size; } virtual Item Get(long index) const { return _arr[index]; } private: ConcreteIterator
*_iter; long _size; Item _arr[DEFAULT_CAPACITY]; }; // Collaborations // - A ConcreteIterator keeps track of the current object in the aggregate and // can compute the succeeding object in the traversal. int main() { ConcreteAggregate
aggregate; for (long item = 0; item < 21; ++item) { aggregate.Append(item); } aggregate.Remove(15); ConcreteIterator
*pIterator = aggregate.CreateIterator(); for (pIterator->First(); !pIterator->IsDone(); pIterator->Next()) { cout << pIterator->CurrentItem() << endl; } if (pIterator) { delete pIterator; pIterator = nullptr; } return 0; } /// // 1. How robust is the iterator? It can be dangerous to modify an aggregate while // you'r traversing it. A robust iterator most rely on registering the iterator // with the aggregate. On insertion or removal, the aggregate either adjusts the // internal state of iterators it has produced, or it maintains information // internally to ensure proper traversal. // 2. Polymorphic iterators have another drawback: the client is responsible for // deleting them. This is error-prone, because it's easy to forget to free a // heap-allocated when you're finished with it. And if an exception is triggered, // the iterator object will never be freed.
// 1. Making sure iterators get deleted. Notice that CreateIterator returns a
// newly allocated iterator object. We're responsible for deleting it. If
// we forget, then we've created storage leak. To make life easier for client,
// we'll provide an IteratorPtr that acts as a proxy for an iterator. It takes
// care of cleaning up the Iterator object when it goes out of scope.
// 2. IteratorPtr is always allocated on the stack. C++ automatically takes care
// of calling its destructor, which deletes the real iterator.
/
// Iterator
// - Provide a way to access the elements of an aggregate object sequentially without
// exposing its underlying representation.
//
// Author : ZAsia
// Date : 15/05/14
// Warning : In practice, declaration and implementation should
// be separated(.h and .cpp).
/
#include
using namespace std;
#define DEFAULT_CAPACITY 128
// Iterator
// - defines an interface for accessing and traversing elements.
template
class Iterator
{
public:
virtual void First() = 0;
virtual void Next() = 0;
virtual bool IsDone() const = 0;
virtual Item CurrentItem() const = 0;
};
// forward declaration
template
class ConcreteAggregate;
// ConcreteIterator
// - implements the Iterator interface.
// - keep the track of the current position in the traversal of the aggregate.
//
// - the implementation of ReverseIterator is identical, except its First operation
// positions _current to the end of the ConcreteAggregate, and Next decrements
// _current toward the first item.
template
class ConcreteIterator : public Iterator
{ public: ConcreteIterator(const ConcreteAggregate
*aggr) : _aggr(aggr), _current(0) { } // First positions the iterator to the first element. virtual void First() { _current = 0; } // Next advances the current element. virtual void Next() { if (_current < _aggr->Count()) { ++_current; } } // IsDone checks whether the index refers to an element within the List. virtual bool IsDone() const { return _current >= _aggr->Count(); } // CurrentItem returns the item at the current index. // If the iteration has already terminated, then throw an exception. virtual Item CurrentItem() const { if (IsDone()) { cout << "Iterator out of bounds." << endl; return 0; } return _aggr->Get(_current); } private: const ConcreteAggregate
*_aggr; long _current; }; // Aggregate // - defines an interface for creating an Iterator object. template
class Aggregate { public: Aggregate( ) { } virtual ~Aggregate() { } virtual ConcreteIterator
*CreateIterator() = 0; virtual void Append(Item item) = 0; virtual void Remove(Item item) = 0; virtual long Count() const = 0; virtual Item Get(long index) const = 0; }; // ConcreteAggregate // - implements the Iterator creation interface to return an instance of the // proper ConcreteIterator. template
class ConcreteAggregate : public Aggregate
{ public: ConcreteAggregate() : _size(0), _iter(nullptr) { } virtual ConcreteIterator
*CreateIterator() { if (_iter) { return _iter; } return new ConcreteIterator
(this); } virtual void Append(Item item) { if (_size > DEFAULT_CAPACITY) { cout << "Aggregate out of capacity." << endl; return; } _arr[_size++] = item; } virtual void Remove(Item item) { if (_size == 0) { return; } for (int i = 0; i < _size; ++i) { if (_arr[i] == item) { for (int j = i; j < _size - 1; ++j) { _arr[j] = _arr[j + 1]; } --_size; } } } virtual long Count() const { return _size; } virtual Item Get(long index) const { return _arr[index]; } private: ConcreteIterator
*_iter; long _size; Item _arr[DEFAULT_CAPACITY]; }; // IteratorPtr // 1. Making sure iterators get deleted. Notice that CreateIterator returns a // newly allocated iterator object. We're responsible for deleting it. If // we forget, then we've created storage leak. To make life easier for client, // we'll provide an IteratorPtr that acts as a proxy for an iterator. It takes // care of cleaning up the Iterator object when it goes out of scope. // 2. IteratorPtr is always allocated on the stack. C++ automatically takes care // of calling its destructor, which deletes the real iterator. template
class IteratorPtr { public: IteratorPtr(Iterator
*i) : _i(i) { } ~IteratorPtr() { delete _i; } Iterator
*operator->() { return _i; } Iterator
&operator*() { return *_i; } private: // disallow copy and assignment to avoid multiple deletions of _i IteratorPtr(const IteratorPtr &ip) { } IteratorPtr &operator=(const IteratorPtr &rs) { } private: Iterator
*_i; }; // Collaborations // - A ConcreteIterator keeps track of the current object in the aggregate and // can compute the succeeding object in the traversal. int main() { ConcreteAggregate
aggregate; for (long item = 0; item < 21; ++item) { aggregate.Append(item); } aggregate.Remove(15); // ConcreteIterator
*pIterator = aggregate.CreateIterator(); IteratorPtr
iterator(aggregate.CreateIterator()); for (iterator->First(); !iterator->IsDone(); iterator->Next()) { cout << iterator->CurrentItem() << endl; } // if (pIterator) // { /// delete pIterator; // pIterator = nullptr; // } return 0; } /// // 1. How robust is the iterator? It can be dangerous to modify an aggregate while // you'r traversing it. A robust iterator most rely on registering the iterator // with the aggregate. On insertion or removal, the aggregate either adjusts the // internal state of iterators it has produced, or it maintains information // internally to ensure proper traversal. // 2. Polymorphic iterators have another drawback: the client is responsible for // deleting them. This is error-prone, because it's easy to forget to free a // heap-allocated when you're finished with it. And if an exception is triggered, // the iterator object will never be freed.