Auswahl const-Funktion vs. Non-const-Funktion



  • Hallo, gut im neuen Jahr gestartet? 😉

    Ich hätte gleich wieder eine Frage. Momentan arbeite ich mich ein wenig tiefer in Iteratoren ein, dabei habe ich einen kleinen Container geschrieben. const_iterator ist dabei eine Klasse, die Iteratorfunktionalität bereitstellt, und bei der die Dereferenzierung Const-Zeiger/-Referenzen zurückgibt. Die Klasse iterator ist davon abgeleitet und überschreibt die Dereferenzierungsoperatoren, sodass die referenzierte Objekte veränderbar sind.

    Nun habe ich für den Container diverse Methoden bereitgestellt, einige davon in einer const - und einer normalen Version. Als Beispiel:

    iterator              end();
    const_iterator        end() const;
    

    Da ich nun die Vererbungshierarchie habe, wird die eine Funktion gar nie aufgerufen - iterator ist implizit in const_iterator konvertierbar.

    Dasselbe passiert auch beim Indexoperator, allerdings hier aus einem anderen Grund. Ich habe wieder zwei Deklarationen:

    reference             operator[] (size_type index);
    const_reference       operator[] (size_type index) const;
    

    Selbst wenn ich das Objekt nicht verändere, also beispielsweise einen der folgenden Aufrufe habe, wird die nicht-konstante Version aufgerufen.

    int a = container[3];
    const int& b = container[3];
    

    Woran liegt das? Ich dachte, es werde automatisch die Version gesucht, bei der möglichst viele Qualifizierer vorhanden sind. Oder wie macht man das richtig?

    Edit: Ich hab mir dazu gerade noch was überlegt. Könnte es sein, dass man die beiden Versionen der Memberfunktionen nur schreibt, um auch bei konstanten Containern gewisse Operationen zu erlauben?



  • Nexus schrieb:

    Edit: Ich hab mir dazu gerade noch was überlegt. Könnte es sein, dass man die beiden Versionen der Memberfunktionen nur schreibt, um auch bei konstanten Containern gewisse Operationen zu erlauben?

    Genau. Wenn es die const-Varianten der Memberfunktionen nicht gäbe, dann wären konstante Container ja praktisch wertlos, da es nichts gäbe, was man damit noch machen könnte.



  • Okay, danke für die Bestätigung. Ich hatte drum noch im Hinterkopf, dass die const -Varianten hier noch einen anderen Zweck hätten... Aber scheinbar nicht. 😉



  • Nexus schrieb:

    [...] habe ich einen kleinen Container geschrieben. const_iterator ist dabei eine Klasse, die Iteratorfunktionalität bereitstellt, und bei der die Dereferenzierung Const-Zeiger/-Referenzen zurückgibt. Die Klasse iterator ist davon abgeleitet und überschreibt die Dereferenzierungsoperatoren, sodass die referenzierte Objekte veränderbar sind.

    😮 😮 Ein iterator ist also ein const_iterator ? (Oder verwendest du keine public-Vererbung?)

    Felix



  • iterator und const_iterator sind nicht verwandt. das bedeutet dass man hier doppelten Code schreiben muss, oder aber boost verwenden: http://www.boost.org/doc/libs/1_37_0/libs/iterator/doc/index.html#iterator-facade-and-adaptor



  • Ich habe auch schon gehört, dass man das besser nicht tun soll. Aber die Standardbibliothek macht es ja auch so, zumindest in meiner Implementierung (MSVC++ 2008 Express):

    template<class _Ty,
    	class _Alloc>
    	class _Vector_iterator
    		: public _Vector_const_iterator<_Ty, _Alloc>
    	{	
    		// ...
    	}
    

    Was ist denn daran so schlecht?



  • Würde mich jetzt schon noch interessieren, was gegen die Vererbung spräche, zumal der Standard es bei mir auch so macht. Klar, von der Logik her ist es nicht sehr intuitiv ( iterator ist ein const_iterator ), aber andererseits besitzt ein iterator die gesamte Funktionalität eines const_iterator s und noch darüber hinaus.



  • Du kannst die iteratoren ploetzlich polymorph verwenden.

    Die wirkliche Frage sollte eher sein:
    warum will ich hier Vererbung haben?

    Die Antwort ist: weil es mir schreibarbeit erspart.

    Und damit sollte das Thema erledigt sein. Denn "weil es mir schreibarbeit erspart" ist meistens ein guter Hinweis auf einen Designfehler.

    Vererbung ist eine enorm starke Bindung die ich nur eingehen will, wenn es mir einen wirklichen Vorteil bringt. Aber die Boost Iterator Facade/Adapter Sachen ersparen mir Kopplung und Schreibarbeit im Vergleich zu der Vererbungsvariante.

    Der wirkliche Grund warum viele Standard Libraries iteratoren so implementieren ist weil es einfach und standard konform ist. Aber ist es deshalb gut?



  • Shade Of Mine schrieb:

    Der wirkliche Grund warum viele Standard Libraries iteratoren so implementieren ist weil es einfach und standard konform ist. Aber ist es deshalb gut?

    Ja, weil es unnötige Codeduplizierung vermeidet, und damit entsprechende Copy and Paste Fehler minimiert.



  • und ich dachte immer, öffnetliche erblichkeit würde IST EIN bedeuten.
    da fällt mir nur http://www.c-plusplus.net/forum/viewtopic-var-t-is-75672-and-highlight-is-bebel.html zu ein.



  • volkard schrieb:

    und ich dachte immer, öffnetliche erblichkeit würde IST EIN bedeuten.
    da fällt mir nur http://www.c-plusplus.net/forum/viewtopic-var-t-is-75672-and-highlight-is-bebel.html zu ein.

    Private Vererbung wäre vielleicht angebrachter.



  • Tachyon schrieb:

    Shade Of Mine schrieb:

    Der wirkliche Grund warum viele Standard Libraries iteratoren so implementieren ist weil es einfach und standard konform ist. Aber ist es deshalb gut?

    Ja, weil es unnötige Codeduplizierung vermeidet, und damit entsprechende Copy and Paste Fehler minimiert.

    Und die Nachteile ignorieren wir einfach?

    natuerlich ist es bequem. aber bequem ist meistens falsch.

    schau dir bitte boost iterator facade/adapter an. du schreibst einen bruchteil von code den du mit der vererbungsvariante brauchst und bist deutlich fehlerfreier.

    wenn du privat vererbst umgehst du zwar die probleme hast aber wieder viel schreibarbeit. und dann wuerde ich sowieso zu layering raten, du hast ein iterator objekt dass alle operationen anbietet und jeweils eine facade fuer iterator und const_iterator drueber...

    aber die richtige wahl ist dennoch boost...



  • volkard schrieb:

    da fällt mir nur http://www.c-plusplus.net/forum/viewtopic-var-t-is-75672-and-highlight-is-bebel.html zu ein.

    Nettes Geschichtlein. 😃

    Ich werde mir wahrscheinlich mal Boost.Iterator anschauen. Danke für die Antworten! 🙂



  • mammamia;


Anmelden zum Antworten