Virtual Iterators

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • richard.forrest1

    Virtual Iterators

    I have a problem with an abstract interface class whose implementation
    classes need to return different iterator types (but with the same
    value_types etc).

    Classes A and B both conform to the same abstract Interface class. Interface
    has a pair of virtual functions begin() and end() that generate a typical
    STL style range. Classes A and B provide different implementations , maybe
    using different types of container. The problem is that, to conform to the
    interface, A and B must return the same type (or a derived type). They can
    not do this directly as their containers (and hence their iterators) are of
    different types.

    class Interface
    {
    public:
    virtual VirtualIterator begin() = 0;
    virtual VirtualIterator end() = 0;
    };

    class A : public Interface
    {
    public:
    virtual VirtualIterator begin() {return
    make_virtual_it erator(containe r_.begin());}
    virtual VirtualIterator end() {return
    make_virtual_it erator(containe r_.end());}
    private:
    OneKindOfContai ner container_;
    };

    class B : public Interface
    {
    public:
    virtual VirtualIterator begin() {return
    make_virtual_it erator(containe r_.begin());}
    virtual VirtualIterator end() {return
    make_virtual_it erator(containe r_.end())}
    private:
    AnotherKindOfCo ntainer container_;
    };

    I think I see how to solve this problem by creating (as the example hints
    at) a kind of VirtualIterator class that maintains a pointer to heap based
    copy of the real iterator. But this issue must be fairly common and I would
    much rather reuse a tried and tested solution than roll my own. I looked at
    the boost iterator library but it does not seem to provide what I am looking
    for. This made me a bit concerned because it seems to be very well thought
    out and comprehensive. Is there something fundamentally wrong with what I am
    considering here? Or perhaps there is a really trivial solution I am
    overlooking?

    Richard Forrest






  • Victor Bazarov

    #2
    Re: Virtual Iterators

    "richard.forres t1" <richard.forres t1@ntlworld.com > wrote...[color=blue]
    > I have a problem with an abstract interface class whose implementation
    > classes need to return different iterator types (but with the same
    > value_types etc).
    >
    > Classes A and B both conform to the same abstract Interface class.[/color]
    Interface[color=blue]
    > has a pair of virtual functions begin() and end() that generate a typical
    > STL style range. Classes A and B provide different implementations , maybe
    > using different types of container. The problem is that, to conform to the
    > interface, A and B must return the same type (or a derived type). They can
    > not do this directly as their containers (and hence their iterators) are[/color]
    of[color=blue]
    > different types.
    >
    > class Interface
    > {
    > public:
    > virtual VirtualIterator begin() = 0;
    > virtual VirtualIterator end() = 0;
    > };
    >
    > class A : public Interface
    > {
    > public:
    > virtual VirtualIterator begin() {return
    > make_virtual_it erator(containe r_.begin());}
    > virtual VirtualIterator end() {return
    > make_virtual_it erator(containe r_.end());}
    > private:
    > OneKindOfContai ner container_;
    > };
    >
    > class B : public Interface
    > {
    > public:
    > virtual VirtualIterator begin() {return
    > make_virtual_it erator(containe r_.begin());}
    > virtual VirtualIterator end() {return
    > make_virtual_it erator(containe r_.end())}
    > private:
    > AnotherKindOfCo ntainer container_;
    > };
    >
    > I think I see how to solve this problem by creating (as the example hints
    > at) a kind of VirtualIterator class that maintains a pointer to heap based
    > copy of the real iterator. But this issue must be fairly common and I[/color]
    would[color=blue]
    > much rather reuse a tried and tested solution than roll my own. I looked[/color]
    at[color=blue]
    > the boost iterator library but it does not seem to provide what I am[/color]
    looking[color=blue]
    > for. This made me a bit concerned because it seems to be very well thought
    > out and comprehensive. Is there something fundamentally wrong with what I[/color]
    am[color=blue]
    > considering here? Or perhaps there is a really trivial solution I am
    > overlooking?[/color]

    For now, having only thought about your problem for a minute, I have only
    one question: what are you going to do with 'VirtualIterato r'? What does
    its interface look like? I can see it that you are going to compare its
    value to 'end' to know when to stop iterating, but I cannot imagine yet
    if you have two different and unrelated containers, what else you could
    do with a VirtualIterator object. Unless, of course, it's an iterator that
    conforms to the iterator semantics laid out in the Standard, then it has to
    have 'value_type' and 'reference' and ...

    Do you have the answers?

    V


    Comment

    • Siemel Naran

      #3
      Re: Virtual Iterators

      "Victor Bazarov" <v.Abazarov@com Acast.net> wrote in message
      news:s_pbc.1691 65$po.978501@at tbi_s52...[color=blue]
      > "richard.forres t1" <richard.forres t1@ntlworld.com > wrote...[/color]
      [color=blue][color=green]
      > > I have a problem with an abstract interface class whose implementation
      > > classes need to return different iterator types (but with the same
      > > value_types etc).
      > >
      > > Classes A and B both conform to the same abstract Interface class.[/color]
      > Interface[color=green]
      > > has a pair of virtual functions begin() and end() that generate a[/color][/color]
      typical[color=blue][color=green]
      > > STL style range. Classes A and B provide different implementations ,[/color][/color]
      maybe[color=blue][color=green]
      > > using different types of container. The problem is that, to conform to[/color][/color]
      the[color=blue][color=green]
      > > interface, A and B must return the same type (or a derived type). They[/color][/color]
      can[color=blue][color=green]
      > > not do this directly as their containers (and hence their iterators) are[/color]
      > of[color=green]
      > > different types.
      > >
      > > class Interface
      > > {
      > > public:
      > > virtual VirtualIterator begin() = 0;
      > > virtual VirtualIterator end() = 0;
      > > };
      > >
      > > class A : public Interface[/color][/color]
      [color=blue]
      > For now, having only thought about your problem for a minute, I have only
      > one question: what are you going to do with 'VirtualIterato r'? What does
      > its interface look like? I can see it that you are going to compare its
      > value to 'end' to know when to stop iterating, but I cannot imagine yet
      > if you have two different and unrelated containers, what else you could
      > do with a VirtualIterator object. Unless, of course, it's an iterator[/color]
      that[color=blue]
      > conforms to the iterator semantics laid out in the Standard, then it has[/color]
      to[color=blue]
      > have 'value_type' and 'reference' and ...[/color]

      I imagine you can pass VirtualIterator to standard functions like std::copy.
      Here is one implementation. It has to be copy constructible, so it won't be
      a polymorphic class. It will define a nested polymorphic abstract class
      implement that represents the real iterator (though it does not have to be a
      nested class), and this class will have pure virtual functions for cloning,
      assigment, increment, decrement, equal. VirtualIterator will contain a
      std::auto_ptr<i mplement> or the like. Derived classes like class A above
      will define concrete iterator implement classes. Here is my implementation.


      template <class T>
      class poly_iterator
      {
      public:
      typedef std::forward_it erator_tag iterator_catego ry;
      typedef T value_type ;
      typedef T & reference ;
      ...

      class implement; // abstract class

      poly_iterator(i mplement * iter) : d_iter(iter) {} // take ownership of
      object
      poly_iterator(c onst poly_iterator& that) :
      d_iter(that.d_i ter->clone()) { }
      poly_iterator& operator=(const poly_iterator& that);
      ~poly_iterator( ) { delete d_iter; }

      bool operator==(cons t poly_iterator& that) const
      { same(*this,that ); return this->d_iter->equal(*that.d_ iter); }
      bool operator!=(cons t poly_iterator& that) const;

      reference operator*() const { return d_iter->get(); }
      pointer operator->() const { return &d_iter->get(); }
      poly_iterator& operator++() { d_iter->next(); return *this; }


      public:
      class implement
      {
      public:
      virtual ~implement() { }
      virtual implement * clone() const = 0;
      virtual bool equal(const implement&) const = 0;
      virtual T& get() const = 0;
      virtual void next() = 0;
      virtual void prev() = 0;
      };

      template <class Iter>
      class usualimplement : public implement {
      public:
      typedef Iter actual_iterator ;
      explicit usualimplement( Iter iter) : d_iter(iter) { }
      usualimplement * clone() const { return new
      usualimplement( *this); }
      bool equal(const implement& that) const { return this->d_iter
      ==static_cast<c onst usualimplement& >(that).d_ite r; }
      T& get() const { return *d_iter; }
      void next() { ++d_iter; }
      void prev() { --d_iter; }
      private:
      Iter d_iter;
      };


      private:
      implement * d_iter; // dynamically created object

      static void same(const poly_iterator& lhs, const poly_iterator& rhs)
      { assert(typeid(* lhs.d_iter)==ty peid(*rhs.d_ite r)); }
      };


      Comment

      • Victor Bazarov

        #4
        Re: Virtual Iterators

        "Siemel Naran" <SiemelNaran@RE MOVE.att.net> wrote...[color=blue]
        > "Victor Bazarov" <v.Abazarov@com Acast.net> wrote in message
        > news:s_pbc.1691 65$po.978501@at tbi_s52...[color=green]
        > > "richard.forres t1" <richard.forres t1@ntlworld.com > wrote...[/color]
        >[color=green][color=darkred]
        > > > I have a problem with an abstract interface class whose implementation
        > > > classes need to return different iterator types (but with the same
        > > > value_types etc).
        > > >
        > > > Classes A and B both conform to the same abstract Interface class.[/color]
        > > Interface[color=darkred]
        > > > has a pair of virtual functions begin() and end() that generate a[/color][/color]
        > typical[color=green][color=darkred]
        > > > STL style range. Classes A and B provide different implementations ,[/color][/color]
        > maybe[color=green][color=darkred]
        > > > using different types of container. The problem is that, to conform to[/color][/color]
        > the[color=green][color=darkred]
        > > > interface, A and B must return the same type (or a derived type). They[/color][/color]
        > can[color=green][color=darkred]
        > > > not do this directly as their containers (and hence their iterators)[/color][/color][/color]
        are[color=blue][color=green]
        > > of[color=darkred]
        > > > different types.
        > > >
        > > > class Interface
        > > > {
        > > > public:
        > > > virtual VirtualIterator begin() = 0;
        > > > virtual VirtualIterator end() = 0;
        > > > };
        > > >
        > > > class A : public Interface[/color][/color]
        >[color=green]
        > > For now, having only thought about your problem for a minute, I have[/color][/color]
        only[color=blue][color=green]
        > > one question: what are you going to do with 'VirtualIterato r'? What[/color][/color]
        does[color=blue][color=green]
        > > its interface look like? I can see it that you are going to compare its
        > > value to 'end' to know when to stop iterating, but I cannot imagine yet
        > > if you have two different and unrelated containers, what else you could
        > > do with a VirtualIterator object. Unless, of course, it's an iterator[/color]
        > that[color=green]
        > > conforms to the iterator semantics laid out in the Standard, then it has[/color]
        > to[color=green]
        > > have 'value_type' and 'reference' and ...[/color]
        >
        > I imagine you can pass VirtualIterator to standard functions like[/color]
        std::copy.

        std::copy is not a function. It's a template.
        [color=blue]
        > Here is [...][/color]

        I still would like to hear from the OP...


        Comment

        • richard.forrest1

          #5
          Re: Virtual Iterators


          "Victor Bazarov" <v.Abazarov@com Acast.net> wrote in message
          news:JFqbc.1646 92$_w.1794464@a ttbi_s53...[color=blue]
          > "Siemel Naran" <SiemelNaran@RE MOVE.att.net> wrote...[color=green]
          > > "Victor Bazarov" <v.Abazarov@com Acast.net> wrote in message
          > > news:s_pbc.1691 65$po.978501@at tbi_s52...[color=darkred]
          > > > "richard.forres t1" <richard.forres t1@ntlworld.com > wrote...[/color]
          > >[/color][/color]


          I have just done a Google search on "polymorphi c iterator" and it is a well
          known concept. There is even a reference to it in GOF (page 271).

          It seems I was just calling it the wrong thing.

          Thanks for you help guys,

          Richard


          Comment

          • richard.forrest1

            #6
            Re: Virtual Iterators


            ----- Original Message -----
            From: "Victor Bazarov" <v.Abazarov@com Acast.net>
            Newsgroups: comp.lang.c++
            Sent: Saturday, April 03, 2004 5:00 AM
            Subject: Re: Virtual Iterators

            [color=blue]
            > "Siemel Naran" <SiemelNaran@RE MOVE.att.net> wrote...[color=green]
            > > "Victor Bazarov" <v.Abazarov@com Acast.net> wrote in message
            > > news:s_pbc.1691 65$po.978501@at tbi_s52...[color=darkred]
            > > > "richard.forres t1" <richard.forres t1@ntlworld.com > wrote...[/color]
            > >[color=darkred]
            > > > > I have a problem with an abstract interface class whose[/color][/color][/color]
            implementation[color=blue][color=green][color=darkred]
            > > > > classes need to return different iterator types (but with the same
            > > > > value_types etc).
            > > > >
            > > > For now, having only thought about your problem for a minute, I have[/color][/color]
            > only[color=green][color=darkred]
            > > > one question: what are you going to do with 'VirtualIterato r'? What[/color][/color]
            > does[color=green][color=darkred]
            > > > its interface look like? I can see it that you are going to compare[/color][/color][/color]
            its[color=blue][color=green][color=darkred]
            > > > value to 'end' to know when to stop iterating, but I cannot imagine[/color][/color][/color]
            yet[color=blue][color=green][color=darkred]
            > > > if you have two different and unrelated containers, what else you[/color][/color][/color]
            could[color=blue][color=green][color=darkred]
            > > > do with a VirtualIterator object. Unless, of course, it's an iterator[/color]
            > > that[color=darkred]
            > > > conforms to the iterator semantics laid out in the Standard, then it[/color][/color][/color]
            has[color=blue][color=green]
            > > to[color=darkred]
            > > > have 'value_type' and 'reference' and ...[/color][/color][/color]

            First of all I take Siemel Narans hint that VirtualIterator would be better
            named PolymorphicIter ator and have done so from now on. This is really a
            response to Victor's questions. I am looking at Siemel's example code snipet
            now (thanks) and will respond to this when I think I understand it properly.

            The PolymorphicIter ator conforms to one of the STL iterator concepts.
            The purpose of PolymorphicIter ator is that any client of an Interface object
            can iterate through all or part of the range [begin(),end()) without having
            to know the type of the underlying container. Of course the iterators
            underlying the PolymorphicIter ator must have the same value_type etc. They
            must also conform to the PolymorphicIter ator's STL iterator concept.

            I am not trying to write a "universal container class" or anything silly
            like that. All I want to do is provide a limited interface for a client to
            be able to read the a range of attribute values.

            Let me give a simple (contrived) example of the use of this. We have an
            interface class AbstractPolygon and two derived classes ConstantPolygon and
            ChangablePolygo n. A ConstantPolygon object represents a polygon that can not
            be edited. A ChangablePolygo n object represents a polygon whose vertices may
            be inserted or erased.

            AbstractPolygon provides a pair of virtual abstract functions vertexBegin(),
            vertexEnd() that provide a sequence of the vertices of the polygon.
            ConstantPolygon and ChangablePolygo n provide implementations of these
            functions. ConstantPolygon 's underlying representation happens to be a
            vector of vertices. But ChangablePolygo n's underlying representation is
            chosen to be a linked list of vertices.

            Now clients that perform constant operations (e.g. rendering, calculating
            area etc) just need to use AbstractPolygon s. They use the AbstractPolygon 's
            vertexBegin() and vertexEnd() functions to obtain the start and end of the
            range of vertices and iterate through it, doing whatever they do. The
            PolymorphicIter ator hides the fact that the underlying iterator may be a
            vector<Vertex>: :const_iterator or a list<Vertex>::c onst_iterator.

            Of course there are other ways to solve this problem. We could provide a new
            virtual abstract member function in AbstractPolygon and a corresponding
            implementation in each derived class for every possible use of the
            iterators. But this couples the algorithms too tightly to the polygons.
            Adding new algorithms would be very inconvienient. Using the Visitor pattern
            might help in some ways but adds its own restrictions. In this case
            PolymorphicIter ators are what are required.


            Thanks for your comments.

            Richard






            Comment

            • richard.forrest1

              #7
              Re: Virtual Iterators


              In case anyone is interested I have just discovered that Boost has a
              polymorphic iterator class being developped right now.
              They call it boost::any_iter ator. It sounds like just what I want :-))))

              See link for details.

              rConstruction


              Thanks once again.

              Richard


              Comment

              Working...