Iterator returning a reference to object of an abstract class?

Discussion in 'C++' started by Belebele, Feb 7, 2007.

  1. Belebele

    Belebele Guest

    I have an Element class which is abstract and I would like to have an
    object of the Iterator class to iterate over a range of elements.

    I would like to use std::for_each to instrument the iteration, which
    forces me to have certain interface on the Iterator class.

    struct Element {
    virtual ~Element() = 0;
    };

    struct Iterator {
    bool operator!=(Iterator const& ) const;
    Iterator& operator++();

    // The returned value of this function is the motivation of my
    post
    // Please, see the comments below the code.
    Element& operator*() const;
    };

    struct Range {
    Iterator begin() const;
    Iterator end() const;
    };


    and the client code:

    void action(Element const& );
    void main()
    {
    Range range;
    std::for_each(range.begin(), range.end(), action);
    }


    Now, after reading some earlier posts, I get the impression that
    experience dictates that iterators should return objects by value. In
    my case, however, the Element class is abstract, and therefore I
    cannot return an object of that class by value.

    I must also point out that in this case, so far clients are not
    interested in holding references to values returned by the iterator
    beyond the next call to operator*. They simply want to use the objects
    and forget about them prior to getting the next object from the
    iterator.

    Thus, I see no need to return pointers (smart pointers, or what have
    you) to objects allocated in the heap. Having said that however, I
    should expect that, in the future, new clients may require to hold
    references to objects beyond the next call to the operator* on the
    iterator. In anticipation of that need, I would like to come up with a
    design that, while it does not add lots of unnecessary complexity,
    will effortlessly accommodate that future need.

    Any comments?
     
    Belebele, Feb 7, 2007
    #1
    1. Advertising

  2. Belebele wrote:
    > I have an Element class which is abstract and I would like to have an
    > object of the Iterator class to iterate over a range of elements.
    >
    > I would like to use std::for_each to instrument the iteration, which
    > forces me to have certain interface on the Iterator class.
    >
    > struct Element {
    > virtual ~Element() = 0;
    > };
    >
    > struct Iterator {
    > bool operator!=(Iterator const& ) const;
    > Iterator& operator++();
    >
    > // The returned value of this function is the motivation of my
    > post
    > // Please, see the comments below the code.
    > Element& operator*() const;
    > };
    >
    > struct Range {
    > Iterator begin() const;
    > Iterator end() const;
    > };
    >
    >
    > and the client code:
    >
    > void action(Element const& );
    > void main()


    int main()

    > {
    > Range range;
    > std::for_each(range.begin(), range.end(), action);
    > }
    >
    >
    > Now, after reading some earlier posts, I get the impression that
    > experience dictates that iterators should return objects by value.


    Oh, what nonsense! Now you're falling into another extreme. First,
    your iterator owned the object and returned a reference to it upon
    request, but then the reference would become invalid as soon as the
    iterator moves onto the next object (which prompted me to suggest
    retuning an object instead). Now, the object is actually owned by
    the "Range", and there is no concern about the validity of the
    reference returned by the iterator. So, return a reference. It's
    going to be valid as long as the Range where the object lives keeps
    it valid. IOW, disconnect the object and the iterator. Only have
    the connection between the iterator and the container it traverses.

    > [..]
    >
    > Any comments?


    If your "Iterator" is specific to your "Range", you should make
    the Iterator class a nested class in Range, most likely. Thus
    a semantic relation will be established and the design intent will
    be very clear.

    V
    --
    Please remove capital 'A's when replying by e-mail
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Feb 7, 2007
    #2
    1. Advertising

  3. Belebele a écrit :
    > I have an Element class which is abstract and I would like to have an
    > object of the Iterator class to iterate over a range of elements.
    >
    > I would like to use std::for_each to instrument the iteration, which
    > forces me to have certain interface on the Iterator class.
    >
    > struct Element {
    > virtual ~Element() = 0;
    > };


    How do you handle affectation with operator=() or copy construtor?
    Each subclass should define a Derived::eek:perator=(const Element& );
    Which limit the usage of Element or do you have a specific interface you
    did not mentionned here (like some protected deep copy operator) ?

    This kind of case never happen in the STL because you cannot define a
    container of pure abstract class (unless by pointer).

    >
    > struct Iterator {
    > bool operator!=(Iterator const& ) const;
    > Iterator& operator++();
    >
    > // The returned value of this function is the motivation of my
    > post
    > // Please, see the comments below the code.
    > Element& operator*() const;
    > };


    If you want to create a STL iterator, you must define traits for your
    iterator (google for it and you will find models).

    >
    > struct Range {
    > Iterator begin() const;
    > Iterator end() const;
    > };
    >
    >
    > and the client code:
    >
    > void action(Element const& );
    > void main()
    > {
    > Range range;
    > std::for_each(range.begin(), range.end(), action);
    > }
    >
    >
    > [snip: answered by Victor Bazarov]
    >
    > I must also point out that in this case, so far clients are not
    > interested in holding references to values returned by the iterator
    > beyond the next call to operator*. They simply want to use the objects
    > and forget about them prior to getting the next object from the
    > iterator.


    If you are only interested in the for_each algorithm with begin() and
    end() as parameter, you would better create a member function
    template<typename Functor>Range::for_each(Functor& f) that iterate the
    functor on all elements. That would save you the cost of defining an
    iterator and make Array a container.

    > [snip: idem]
    > Any comments?


    Michael
     
    Michael DOUBEZ, Feb 7, 2007
    #3
  4. Belebele

    Belebele Guest

    On Feb 7, 5:24 pm, Michael DOUBEZ <> wrote:
    > Belebele a écrit :
    >
    > > I have an Element class which is abstract and I would like to have an
    > > object of the Iterator class to iterate over a range of elements.

    >
    > > struct Element {
    > > virtual ~Element() = 0;
    > > };

    >
    > How do you handle affectation with operator=() or copy construtor?
    > Each subclass should define a Derived::eek:perator=(const Element& );
    > Which limit the usage of Element or do you have a specific interface you
    > did not mentionned here (like some protected deep copy operator) ?


    So far, I have not had a need for neither shallow- nor deep-copy
    semantics, so yes, I hide both the copy constructor and the operator=.

    > If you are only interested in the for_each algorithm with begin() and
    > end() as parameter, you would better create a member function
    > template<typename Functor>Range::for_each(Functor& f) that iterate the
    > functor on all elements. That would save you the cost of defining an
    > iterator and make Array a container.


    Even though I have only seen the need to traverse the entire sequence,
    I am pretty sure I will be using other algorithms pretty soon.
     
    Belebele, Feb 7, 2007
    #4
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Matthias Kaeppler
    Replies:
    1
    Views:
    470
    R.F. Pels
    May 22, 2005
  2. Sameer
    Replies:
    4
    Views:
    632
    Roedy Green
    Aug 31, 2005
  3. Uzytkownik
    Replies:
    3
    Views:
    610
    Uzytkownik
    Apr 3, 2005
  4. Iyer, Prasad C

    Abstract Methods & Abstract Class

    Iyer, Prasad C, Oct 20, 2005, in forum: Python
    Replies:
    0
    Views:
    550
    Iyer, Prasad C
    Oct 20, 2005
  5. Replies:
    4
    Views:
    864
    Rolf Magnus
    May 17, 2006
Loading...

Share This Page