base class for iterators?



  • Hy
    Problem: ich habe 2 stl-container (z.B. vector<C> und list<C>)
    und ich möchte code schreiben, der mittels der iteratoren beide container bearbeiten kann.

    Ich weiss, Standardansatz wäre eine template-funktion zu schreiben, die den container als templateargument hat, aber das ist bei mir unpraktikabel.
    Soweit ich weiss gibt es auch keine gemeinsame base class für die stl-container.

    Frage: gibt es eine base class für die iteratoren der verschiedenen container, oder ist es möglich sich sowas zu bauen???

    etwa in der art:

    class base_iterator
    {
    ?????? gesuchter code; vermutlich muss dies auch eine template classe sein, oder so.
    };

    function(base_iterator i){some code}; //soll keine template funktion sein!!

    vector<C> A;
    vector<C>::iterator ia=A.begin();
    list<C> B;
    list<C>::iterator ib=B.begin();

    function(ia);
    function(ib);

    oder meinetwegen auch

    function(base_iterator(ia)) oder mit static cast oder so.

    Danke schonmal für eure tipps, Andi



  • blubbersprudel schrieb:

    Hy
    Problem: ich habe 2 stl-container (z.B. vector<C> und list<C>)
    und ich möchte code schreiben, der mittels der iteratoren beide container bearbeiten kann.

    Ich weiss, Standardansatz wäre eine template-funktion zu schreiben, die den container als templateargument hat, aber das ist bei mir unpraktikabel.
    Soweit ich weiss gibt es auch keine gemeinsame base class für die stl-container.

    Frage: gibt es eine base class für die iteratoren der verschiedenen container, oder ist es möglich sich sowas zu bauen???

    etwa in der art:

    class base_iterator
    {
    ?????? gesuchter code; vermutlich muss dies auch eine template classe sein, oder so.
    };

    function(base_iterator i){some code}; //soll keine template funktion sein!!

    vector<C> A;
    vector<C>::iterator ia=A.begin();
    list<C> B;
    list<C>::iterator ib=B.begin();

    function(ia);
    function(ib);

    oder meinetwegen auch

    function(base_iterator(ia)) oder mit static cast oder so.

    Danke schonmal für eure tipps, Andi

    Hallo, ne Basisklasse gibt es nicht.

    Eine Lösung wäre, ne "Adapter" Klasse zu schreiben:

    class iterator_adapter {
      public:
        iterator_adapter(std::list<C>::iterator begin, std::list<C>::iterator end);
        iterator_adapter(std::vector<C>::iterator ...);
    
        // iterator funktionen ...
    
      private:
    };
    

    Intern speicherst du die iteratoren entweder über ne Art union, wo entweder die von list oder von vector benutzt werden oder du nimmst boost::any // boost::variant oder einfach Templates 😉

    Du könntest natürlich auch iterator_adapter als Basisklasse nehmen und dann jeweils für vector und list ableiten aber das ist alles viel umständlicher als Templates.



  • blubbersprudel schrieb:

    Ich weiss, Standardansatz wäre eine template-funktion zu schreiben, die den container als templateargument hat, aber das ist bei mir unpraktikabel.

    Darf man fragen, warum dieser Ansatz nicht praktikabel ist (Nur so aus interesse)?



  • Also erstmal vielen dank für den Tipp. Das mit dem Adapter sieht ganz vielversprechend aus. Allerdings etwas umstandlich, das ich ja ein constructor für jede mögliche containerklasse schreiben muss.

    Der Templateansatz ist für mich ungeschickt, da meine klasse eine basisklasse für 6-8 andere ist, deren funktionen unter anderem auch iteratoren zurücklifern. D.h. alle Klassen, die diese funktionen benutzen müssen auch wieder Templates sein, und dass passt mir gar nicht, wird unschön und umständlich.

    An einer anderen stelle taucht ein ähnliches problem auf, Da muss ich einen iterator speichern, der typ des iterators soll sich aber zur laufzeit ändern können. Das geht natürlich auch einfach mit polimorphie, aber ich wollt gern was anderes probieren.

    nochmal Danke



  • Ich stell gerade fest, das ich bei den adapter-ansatz die ganzen iterator funktionen (++ += ...) auch neu schreiben muss. Das wird ne ganze Menge, wenn ich das für alle container machen muss, und wirkt sich das nicht auf die Laufzeit negativ aus (auch wenn ich alle funktionen inline schreibe)??

    Danke, blubber



  • Vermutlich ja (vor allem wegen der ganzen Prüfungen ala "welchen Iterator habe ich gerade?"). Deswegen verwendet die STL auch Templates, um flexibel zu bleiben: du kannst einem Algorithmus alles mitgeben, was du willst - solange es die nötigen Operationen (++, *, +=,...) unterstützt, klappt der Algorithmus.

    PS: Es gibt übrigens eine Klasse "std::iterator", die als Basis zur Konstruktion eigener Iteratoren verwendet werden kann. Aber niemand zwingt dich, diese Klasse zu nutzen.

    PPS: Eventuell könntest du auch Polymorphie selber einbauen:

    //Idee ungetestet
    template<typename T>
    class iterator_base
    {
    public:
      virtual T& operator*() =0;
      virtual iterator_base& operator++() =0;
      ...
    };
    
    template<typename T,typename It>
    class iterator : public iterator_base<T>
    {
      It my_it;
    public:
      iterator(It iter) : my_it(iter);
    
      virtual T& operator*() {return *my_it;}
      virtual iterator_base<T>& operator++() {++my_it;return *this;}
      ...
    };
    


  • Der Templateansatz ist für mich ungeschickt, da meine klasse eine basisklasse für 6-8 andere ist, deren funktionen unter anderem auch iteratoren zurücklifern. D.h. alle Klassen, die diese funktionen benutzen müssen auch wieder Templates sein, und dass passt mir gar nicht, wird unschön und umständlich.

    Anhand das du iteratoren brauchst, vermut ich, das deine klasse nen container + etwas mehr repraesentiert. In ner typsicheren sprache willst du quasi nen container mit undefienierten verhalten und variablen inhaltstyp bauen, der auch noch von anderen klassen abgeleitet wird ^^
    Naja, dass dir das c++ ned einfach macht, kann ich mir vorstellen ^^

    du solltest deine vererbung noch mal ueberdenken, generische container gehoeren eher richtung java als nach c++

    iteratoren vererben wird dir c++ soweiso ned leicht machen ... weil operatoren ned wirklich virtuell sind (ok, kann man durch delegation an members loesen) aber spaetestens den dereferenzierungsoperator wirst so nicht hinbekommen (typsicher).

    ich wuerd in c++ nur typisierte contaiener verwenden ... und eher die elemente die in den conateiner muessen durch einen Adapter anpassen !

    das verhalten (list oder vector) wirst auch nicht polymorph abbilden koennen, weil die iteratoren ja schon mal unterschiedliches verhalten haben ... dann lieber durch templetes typisieren ....

    Ciao ...


Log in to reply