Map ableiten und iterator "verstecken"



  • Hallo! 🤡

    Mein Klasse hat die Basis std::map und eigendlich soll auch alles public sein, iterator jedoch portected. (const_iterator auch public)

    Ist das irgendwie möglich?

    Danke 😮



  • Pigeon@work schrieb:

    Hallo! 🤡

    Mein Klasse hat die Basis std::map und eigendlich soll auch alles public sein, iterator jedoch portected. (const_iterator auch public)

    Ist das irgendwie möglich?

    Danke 😮

    Nein, zum Glück nicht: Richtig vererben...
    Von STL-Containern zu erben ist auch nicht vorgesehen...



  • Das man nicht von std Containern erben soll habe ich nun öfter gehört. Gibts dafür auch einen Grund? 🙄

    Was wäre denn "richtig"? std::map wrappen?! 😕

    Danke für die schnelle Antwort 🙂



  • Pigeon@work schrieb:

    Das man nicht von std Containern erben soll habe ich nun öfter gehört. Gibts dafür auch einen Grund? 🙄

    Was wäre denn "richtig"? std::map wrappen?! 😕

    Danke für die schnelle Antwort 🙂

    Der Hauptgrund liegt darin, dass die STL-Container keine virtuellen Destruktoren haben. Dadurch kann man schnell undefiniertes Verhalten produzieren, wenn man z.B. für einen Basiszeiger (der Container) abgeleitete Klassenobjekt löscht.

    Einen "Wrapper" bzw. den gewünschten Container als Aggregat für eigene Klassen zu benutzen, wäre hier der richtige Ansatz.

    PS: Ein gutes Beispiel, wie man es richtig macht, sind übrigens die Adaptertemplates der STL.
    std::queue ist z.B. so ein Adapter. Standardmäßig benutzt er std::deque und schränkt den Zugriff so ein, dass nur noch auf das erste bzw. letzte Element zugegriffen werden kann.



  • Tachyon schrieb:

    ...Der Hauptgrund liegt darin, dass die STL-Container keine virtuellen Destruktoren haben....

    Hmmmm also ich hätte das jetzt eher als "Konsequenz von..." oder "Kennzeichen für ..." und weniger als "Grund" bezeichnet.

    Einen Grund, warum die STL-Designer die Container nicht als mögliche Basisklasse entworfen (und damit virtuelle Destruktoren verpasst) haben, weiß ich auch nicht. Vielleicht aus dem Grund, weswegen Meyers und Sutter dringend zu abstrakten Basisklassen raten...

    Gruß,

    Simon2.



  • Simon2 schrieb:

    Tachyon schrieb:

    ...Der Hauptgrund liegt darin, dass die STL-Container keine virtuellen Destruktoren haben....

    Hmmmm also ich hätte das jetzt eher als "Konsequenz von..." oder "Kennzeichen für ..." und weniger als "Grund" bezeichnet.

    Einen Grund, warum die STL-Designer die Container nicht als mögliche Basisklasse entworfen (und damit virtuelle Destruktoren verpasst) haben, weiß ich auch nicht. Vielleicht aus dem Grund, weswegen Meyers und Sutter dringend zu abstrakten Basisklassen raten...

    Gruß,

    Simon2.

    Die Frage war nicht, wieso die Container nicht so entworfen wurden, dass man nicht ableiten kann, sondern wieso man nicht davon ableiten kann. Und der Grund dafür ist eben, dass der Destruktor nicht virtuell ist.

    Der Grund, weshalb es nicht so entworfen wurde, ist der, dass die Container benutzt werden sollen. Es sollen also nur has-a Beziehungen bestehen. In den wenigsten Fällen kann man die Container so ableiten und spezialisieren, dass tatsächlich eine is-a Beziehung dabei zustande kommt.



  • In meinen Augen ist die Fragestellung "Wieso kann man von Containern nicht ableiten" nicht eindeutig ("Wieso kann mein Auto nicht schneller als 200 fahren ?" => "Weil es dann kaputtginge" <-> "Weil es als Familienkutsche entworfen wurde") Ich hätte die Frage zu Deiner Antwort gestellt als "Woher kann man wissen, dass Container nicht zum ableiten gedacht sind ?"

    Tachyon schrieb:

    ...Der Grund, weshalb es nicht so entworfen wurde, ist der, dass die Container benutzt werden sollen. Es sollen also nur has-a Beziehungen bestehen....

    Das ist ebenfalls nur eine Umformulierung von "Man soll von ihnen nicht ableiten".

    Tachyon schrieb:

    ...In den wenigsten Fällen kann man die Container so ableiten und spezialisieren, dass tatsächlich eine is-a Beziehung dabei zustande kommt.

    Hmmm, also wenn ich mir hier die Anfragen im Forum ansehe, scheint es eine Menge Gründe zu geben, warum Leute "MyVector"-Klassen bauen wollen .... (auch, wenn ich selbst das nicht brauche).

    Gruß,

    Simon2.


  • Mod

    Pigeon@work schrieb:

    Das man nicht von std Containern erben soll habe ich nun öfter gehört. Gibts dafür auch einen Grund?

    Ja, Tachyon hat dir einen guten Link zu dem Problem gegeben. Lies dir alles durch - auch wenn es auf den ersten Blick um etwas anderes zu gehen scheint: dem ist nicht so. Lies es mehrmals. Und erwarte trotzdem nicht, alles sofort verstehen zu können.

    Alles Andere, wie z.B. fehlende virtuelle Destruktoren, sind technische Einzelheiten, die prinzipiell nur als Indiz gelten können.



  • Ist das irgendwie möglich?

    Natürlich ist das möglich.

    class MyMap:private std::map<Foo, Bar>{
      typedef std::map<Foo, Bar> super;
    public:
      using super::size;
      using super::insert;
      ...
    protected:
      using super::iterator;
      using super::begin;
      using super::end;
      ...
    
    };
    

    Per default ist alles was von map geerbt wird private. Durch ein using Konstrukt kannst du das jedoch ändern und du musst es für jeden Member explizit ändern. Upcasten kannst du auch nicht (außerhalb der Klasse zu mindest) und daher gibt es auch kein Problem mit Konstruktoren.

    Einen Grund, warum die STL-Designer die Container nicht als mögliche Basisklasse entworfen (und damit virtuelle Destruktoren verpasst) haben, weiß ich auch nicht.

    Die ganzen Containerklasen der STL verzichten komplett auf Laufzeitpolymorphie und erlauben dem Compiler daher ein sehr agressives Optimieren.



  • Simon2 schrieb:

    In meinen Augen ist die Fragestellung "Wieso kann man von Containern nicht ableiten" nicht eindeutig ("Wieso kann mein Auto nicht schneller als 200 fahren ?" => "Weil es dann kaputtginge" <-> "Weil es als Familienkutsche entworfen wurde") Ich hätte die Frage zu Deiner Antwort gestellt als "Woher kann man wissen, dass Container nicht zum ableiten gedacht sind ?"

    Das ist mal wieder Haarspalterei (mache ich auch gerne 😉 ). Die Frage war aber ausreichend gut formuliert, um sie mit etwas gutem Willen verstehen zu können.

    Simon2 schrieb:

    Tachyon schrieb:

    ...Der Grund, weshalb es nicht so entworfen wurde, ist der, dass die Container benutzt werden sollen. Es sollen also nur has-a Beziehungen bestehen....

    Das ist ebenfalls nur eine Umformulierung von "Man soll von ihnen nicht ableiten".

    Ja. Was ist daran auszusetzen? Ich bezog mich in diesem Falle ja auf Deine Aussagen.

    Simon2 schrieb:

    Tachyon schrieb:

    ...In den wenigsten Fällen kann man die Container so ableiten und spezialisieren, dass tatsächlich eine is-a Beziehung dabei zustande kommt.

    Hmmm, also wenn ich mir hier die Anfragen im Forum ansehe, scheint es eine Menge Gründe zu geben, warum Leute "MyVector"-Klassen bauen wollen .... (auch, wenn ich selbst das nicht brauche).

    In den meisten Fällen passiert das zu Lernzwecken. Da wird dann eh gleich die ganze Vektorlogik neu implementiert, ohne irgendwie von std::vector zu erben. Dabei geht es dann meist irgendwie um Operatorüberladung, dynamisches Speichermanagement etc. Daran ist erstmal nicht so viel auszusetzen.

    In den restlichen Fällen ist es fast ausschließlich so, dass bei der (public) Vererbung von std::vector irgendwie versucht wird, die öffentliche Schnittstelle der Klasse irgendwie einzuschränken.Und das ist schon mal von Ansatz her völlig falsch. Wenn man z.B. wie der OP versucht, Iteratoren zu verbergen, dann ist die Ableitung eben keine Map mehr. Denn dann hätte sie ihre Iteratoren noch.
    Und großartig erweitern lassen sich die Container nicht, da sich die Funktionalität kaum noch sinnvoll erweitern lässt. Zum einen, da man eh nur Zugriff auf die öffentliche Schnittstelle hat, zum anderen, weil sich die Funktionalität aufgrund der fehlenden Virtualität nicht anpassen lässt.
    Das einzige, was in Frage kommt, wäre eine private Ableitung, aber das ist auch nichts anderes, als den Vektor als Member der eigenen Klasse zu halten.



  • Ben04 schrieb:

    ...

    Nur ist das keine Vererbung sondern eine syntaktische Variante einer Aggregation...



  • Tachyon schrieb:

    ...Die Frage war aber ausreichend gut formuliert, um sie mit etwas gutem Willen verstehen zu können...

    Also ich habe eine Menge guten Willen mitgebracht und sie spontan genau so verstanden: "Warum kann man STL-Container nicht ableiten ?" <=> "Was ist der dahinterliegende Sinn ?"

    Tachyon schrieb:

    Simon2 schrieb:

    Tachyon schrieb:

    ...Der Grund, weshalb es nicht so entworfen wurde, ist der, dass die Container benutzt werden sollen. Es sollen also nur has-a Beziehungen bestehen....

    Das ist ebenfalls nur eine Umformulierung von "Man soll von ihnen nicht ableiten".

    Ja. Was ist daran auszusetzen? ...

    Na, dass sie die Frage immer noch nicht beantwortet: "Warum soll (Aggregation (= 'has-a'-Relation) aber) keine Vererbung (= 'is-a'-Relation) unterstützt werden ?"

    Die Beispiele, an die ich mich hier im Forum erinnere, haben durchaus wohlklingende Motivationen (z.B. Konsistenzchecks beim Einfügen).
    Ich persönlich lehne das zwar auch ab, weil ich bislang immer "sauberer" Lösungen ohne Vererbung gefunden habe ... aber echte zwingende Argumente für einen Vektor, der alles herkömmliche UND etwas Zusätzliches kann, habe ich auch nicht.

    Gruß,

    Simon2.



  • Simon2 schrieb:

    Na, dass sie die Frage immer noch nicht beantwortet: "Warum soll (Aggregation (= 'has-a'-Relation) aber) keine Vererbung (= 'is-a'-Relation) unterstützt werden ?"

    Weil es dem Design der STL zuwider läuft. Die STL soll aus möglichst kleinen, benutzbaren Einheiten bestehen. So weit wie möglich sollen generische Algorithmen unabhängig vom verwendeten Container darauf angewandt werden können. Einschränkungen oder Erweiterungen sollen über Adapterklassentemplates realisiert werden. Das war halt die Philosophie beim Design der STL (zumindest, wenn ich die Pamphlete der Macher richtig verstanden habe).

    Um mal auf die "Erweiterung" des Vector-Templates mit Plausiblitätschecks zurückzukommen:
    Hier sollte meistens die Schnittstelle so beschnitten werden, dass nur noch jede Operationen zur Verfügung stehen, die Checks beinhalten.
    Wenn man eine Klasse von Vektor erben lässt, und die erbende Klasse die Schnittstelle so verbiegt, dass alle Zugriffe mit solchen Checks versehen werden, dann ist die abgeleitete Klasse eben kein Vektor mehr. Soll heissen: Es ist eben nicht möglich, überall da, wo man den normalen Vektor benutzen kann auch die abgeleitete Klasse benutzen kann. Und wenn dem so ist, dann ist Vererbung hier eben nicht das Mittel der Wahl.


Anmelden zum Antworten