    In section ref(ITERATORS) the iterators used with generic algorithms were
introduced. We've seen that several types of iterators were distinguished:
InputIterators, ForwardIterators, OutputIterators, BidirectionalIterators and
RandomAccessIterators.

    To ensure that an object of a class is interpreted as a particular type of
iterator, the class must be derived from the class
    hi(iterator)tt(std::iterator).  Before a class can be derived from this
class the tthi(iterator) header file must be included.

    In section ref(ITERATORS) the characteristics of iterators were
discussed. All iterators
        hi(iterator: common characteristics)
        hi(iterator: requirements)
    should support (using tt(Iterator) as the generic name of the designed
iterator class and tt(Type) to represent the (possibly tt(const), in which
case the associated operator should be a tt(const) member as well) data type to
which tt(Iterator) objects refer):
    itemization(
    it() a prefix increment operator (tt(Iterator &operator++()));
    it() a dereference operator (tt(Type &operator*()));
    it() a 'pointer to' operator (tt(Type *operator->()));
    it() comparison operators testing the (in)equality of two iterator objects
(tt(bool operator==(Iterator const &other)), tt(bool operator!=(Iterator const
&other))).
    )

    When
        hi(iterator: and generic algorithms)
    iterators are to be used in the context of generic algorithms they must
meet additional requirements. This is caused by the fact that generic
algorithms perform checks on the types of the iterators they receive. Simple
pointers are usually accepted, but if an iterator-object is used it must be
able to specify the kind of iterator it represents.

    When deriving a class from the class tt(iterator) the
        hi(iterator: class type)
    type of iterator is defined by the class template's em(first) parameter,
and the
        hi(iterator: data type)
    data type to which the iterator refers is defined by the class template's
em(second) parameter.

    The type of iterator that is implemented by the derived class
is specified using a so-called emi(iterator_tag), provided as the
first template argument of the class tt(iterator). For the five basic iterator
types, these tags are:
    itemization(
    itht(input_iterator_tag)(std::input_iterator_tag). This tag defines an
i(InputIterator).  Iterators of this type allow reading operations, iterating
from the first to the last element of the series to which the iterator
refers.

    The InputIterator  dereference operator should be declared as follows:
        verb(
    Type const &operator*() const;
        )
    Except for the standard operators there are no further requirements for
InputIterators.


    itht(output_iterator_tag)(std::output_iterator_tag). This tag defines an
i(OutputIterator).  Iterators of this type allow for assignment operations,
iterating from the first to the last element of the series to which the
iterator refers.

    The OutputIterator  dereference operator should allow assignment to the
data its dereference operator refers to. Therefore, the OutputIterator
dereference operator should be declared as follows:
        verb(
    Type &operator*();
        )
    Except for the standard operators there are no further requirements for
OutputIterators.

    itht(forward_iterator_tag)(std::forward_iterator_tag). This tag defines a
        i(ForwardIterator).  Iterators of this type allow reading em(and)
assignment operations, iterating from the first to the last element of the
series to which the iterator refers.

    The ForwardIterator  dereference operator should allow assignment to the
data its dereference operator refers to. Therefore, the ForwardIterator
dereference operator should be declared as follows:
        verb(
    Type &operator*();
        )
    Except for the standard operators there are no further requirements for
ForwardIterators.


    itht(bidirectional_iterator_tag)(std::bidirectional_iterator_tag). This
tag defines a i(BidirectionalIterator). Iterators of this type allow reading
em(and) assignment operations, iterating step by step, possibly in alternating
directions, over all elements of the series to which the iterator refers.

    The Bidirectional dereference operator should allow assignment to the data
its dereference operator refers to and it should allow stepping
backward. BidirectionalIterator should therefore, in addition to the standard
operators required for iterators, offer the following operators:
        verb(
    Type &operator*();
    Iterator &operator--();
        )

    itht(random_access_iterator_tag)(std::random_access_iterator_tag). This
tag defines a i(RandomAccessIterator).  Iterators of this type allow reading
em(and) assignment operations, iterating, possibly in alternating directions,
over all elements of the series to which the iterator refers using any
available (random) stepsize.

    RandomIterator class dereference operators should allow assignment to the
data they refer to, and, in addition to the standard operators required for
iterators, offer the following operators:
    itemization(
    itt(Type &operator*()), allowing assignment to the data the dereference
operator refers to;
    itt(Iterator &)ttNoCt(operator--()), allowing single steps backward;
    itt(Type operator-(Iterator const &rhs) const), returning the number of
data elements between the current and tt(rhs) iterator (returning a negative
value if tt(rhs) refers to a data element beyond the data element tt(this)
iterator refers to);
    itt(Iterator operator+(int step) const), returning an iterator referring
to a data element tt(step) data elements beyond the data element tt(this)
iterator refers to;
    itt(Iterator operator-(int step) const), returning an iterator referring
to a data element tt(step) data elements before the data element tt(this)
iterator refers to;
    itt(bool operator<(Iterator const &rhs) const), returning tt(true) if
the data element tt(this) iterator refers to is located before the data
element the tt(rhs) iterator refers to.
        )
    )
    Each iterator tag assumes that a certain set of operators is
available. The em(RandomAccessIterator) is the most complex of iterators, as
it implies all other iterators.

    Note that iterators are always defined over a certain range
(rangett(begin, end)). Increment and decrement operations may result in
undefined behavior of the iterator if the resulting iterator value would refer
to a location outside of this range.

    Often, iterators only access the elements of the series to which they
refer. Internally, an iterator may use an ordinary pointer but it is hardly
ever necessary for the iterator to allocate its own memory. Therefore, as the
assignment operator and the copy constructor do not have to allocate any
memory, their em(default implementations) usually suffice.  For the same
reason iterators usually don't require destructors.

    Most classes offering members returning iterators do so by having members
construct the required iterators that are thereupon returned as objects by
those member functions. As the em(caller) of these member functions only has
to em(use) or sometimes em(copy) the returned iterator objects, there is
usually no need to provide any publicly available constructor, except for the
copy constructor. Therefore these constructors are usually defined as
em(private) or em(protected) members. To allow an outer class to create
iterator objects, the iterator class usually declares the outer class as its
em(friend).

    In the following sections the construction of a em(RandomAccessIterator),
the most complex of all iterators, and the construction of a em(reverse
RandomAccessIterator) is discussed. The container class for which a random
access iterator must be developed may actually store its data elements in many
different ways (e.g., using containers or pointers to pointers).  Therefore it
is difficult to construct a template iterator class which is suitable for a
large variety of container classes.

    In the following sections the available tt(std::iterator) class is used to
construct an inner class representing a random access iterator.  The reader
may follow the approach illustrated there to construct iterator classes for
other contexts. An example of such a template iterator class is provided in
section ref(CONCRETEITER).

The random access iterator developed in the next sections reaches data
elements that are only accessible through pointers. The iterator class is
designed as an inner class of a class derived from a vector of string
pointers.
