Iteration

The previous example program shows one way of iterating over a collection. Iteration is done so often with collections that special classes of objects called iterators are provided to make the job easier. Figure 1 shows the protocol for iterators designed to work with arrays.


Like comparators and collections, iterators are defined as class templates. You use templates to instantiate an iterator for a collection containing a particular kind of element. You can create iterators by invoking constructors for a given iterator class, however it's generally easier to use the protocol provided by collections themselves. For example TArrayOf provides two member functions for creating iterators.

          template <class AType>
          class   TArrayOf : public TIndexedSequenceOf<AType>,
                             public TPrimitiveArray {
          public:
              ...
      
          virtual TIteratorOver<AType>*       CreateIterator() const;
          virtual TSequenceOfIterator<AType>* CreateSequenceIterator() const;
              ...
          }
NOTE You can also instantiate iterators directly through their constructors which receive the collection they are to iterate over as an argument.

    TArrayOfIterator<TCollectibleLong> iterator(collection);

Types of iterators

Which type of iterator you create depends on the type of protocol you require for iteration. If you only need First, Next, and Remove, use CreateIterator to instantiate an iterator for your collection. This technique is applicable to all collection classes. If, in addition to the basic protocol defined by
TIteratorOver, you need Previous, and Last, use CreateSequenceIterator.

A point of confusion arises from the fact that for arrays, CreateSequenceIterator returns a TSequenceOfIterator when it might seem it should return a TArrayOfIterator. Actually, a pointer is returned and even though the pointer is of type TSequenceOfIterator, the object it points to is of type TArrayOfIterator. Because the protocol for iteration is defined by virtual functions, the appropriate behavior for iteration is effected through dynamic binding with the iterators returned by either CreateSequenceIterator or CreateIterator.

As the purpose here is to discuss general protocol for collections, focus on iteration using TIteratorOver objects returned by CreateIterator. Because iterator classes are templatized, the specific type returned by CreateIterator depends on the type of element TArrayOf was declared to contain. For an array declared to hold TCollectibleLongs

          TArrayOf<TCollectibleLong>* collection =
              new TArrayOf<TCollectibleLong>(comparator, NIL);
CreateIterator returns a pointer to an instance of TIteratorOver<TCollectibleLong>

          TIteratorOver<TCollectibleLong>* iterator =
              collection->CreateIterator();
The primary protocol you'll use for iterators is implemented by First and Next. Once the iterator is created, use First to set the iterator to point to the first element of the collection.

        iterator->First()
First also validates or initializes the iterator. Don't call Next until you've called First. You want to capture the pointer returned by First as this points to an element in the collection, or is NIL if the collection is empty.

        TCollectibleLong* number = iterator->First();
Normally you would process the current element, number in this case, and then advance the iterator to point to the next element in the collection with Next.

        number = iterator->Next()
As long as there is a subsequent element in the collection, Next will return a pointer to it. When the iterator advances beyond the end of the collection, Next returns NIL. A typical for loop idiom using this protocol looks like this.

          for (TCollectibleLong* number = iterator->First();
               number != NIL;
               number = iterator->Next(), i++) {
              ...
          }

A parameterized function to print collections

This type of loop is used so frequently that it's helpful to define a templatized function for printing the contents of any type of collection that contains a specific kind of element such as TCollectibleLong. This can be done by parameterizing the specific type of collection passed to the function as an argument

      void printCollection(TCollectionOf<TCollectibleLong>* collection)
      {
          ...
      }
A complete definition for a generic printCollection function follows. This function uses an integer variable to keep track of the order of elements in the collection. The integer is increased by one each time iterator->Next() is called.

      void printCollection(TCollectionOf<TCollectibleLong>* collection)
      {
          int i = 0;                          // tracks order of elements
          TIteratorOver<TCollectibleLong>* iterator = collection->CreateIterator();
          for (TCollectibleLong* number = iterator->First();
               number != NIL;
               number = iterator->Next(), i++) {
      
              long aLong = number->GetValue();
              printf("\n%3d> %d", i, aLong);
      
          }
      
          printf("\n");
      
          delete iterator;
      }
The above function is quite useful for experimenting with different types of collections to see how the order of collection elements is affected by the type of collection as well as the order in which elements are added. Note, however, that this function assumes that the elements of the collection to be printed are instances of TCollectibleLong. It is possible to overload printCollection with definitions which accept collections containing different types of elements. This approach provides a generalized technique for dumping the contents of collections.

The following program uses printCollection to print the contents of a collection after for TCollectibleLongs are added to it.

Sample program using printCollection

      // Copyright (c) 1994 Taligent, Inc. All Rights Reserved.
      
      #ifndef Taligent_COLLECTIONS
      #include <Collections.h>
      #endif
      
      #ifndef _H_STDIO
      #include <stdio.h>
      #endif
      
      void printCollection(TCollectionOf<TCollectibleLong>* collection)
      {
          int i = 0;                          // tracks order of elements
          TIteratorOver<TCollectibleLong>* iterator = collection->CreateIterator();
          for (TCollectibleLong* number = iterator->First();
               number != NIL;
               number = iterator->Next(), i++) {
      
              long aLong = number->GetValue();
              printf("\n%3d> %d", i, aLong);
          }
          printf("\n");
          delete iterator;
      }
      
      
      int main()
      {
          TArrayOf<TCollectibleLong>* collection =
              new TArrayOf<TCollectibleLong>(NIL, NIL);
      
          collection->Add(new TCollectibleLong(0));
          collection->Add(new TCollectibleLong(1));
          collection->Add(new TCollectibleLong(2));
          collection->Add(new TCollectibleLong(3));
      
          printCollection(collection);
      
          collection->DeleteAll();
          delete collection;
          return 0;
      }
The output from this program shows the index value of the element followed by the value of the TCollectibleLong at the index position within the collection.

      0> 0
      1> 1
      2> 2
      3> 3

[Contents] [Previous] [Next]
Click the icon to mail questions or corrections about this material to Taligent personnel.
Copyright©1995 Taligent,Inc. All rights reserved.

Generated with WebMaker