von std::vector erben??



  • Daran ist nichts komisch. Wenn eine Klasse keinen virtuellen Dtor hat, ist sie nicht für Vererbung vorgesehen/bestimmt. Ist doch eine ganz einfache Definition?! Eine Klasse die nicht vererbar ist, hat ja trotzdem seine Daseinsberechtigung.

    Wenn du die Vector-Klasse "erweitern" willst, kannst du doch privat "vererben" und mit using die Methoden sichtbar machen:

    class myvector : private std::vector
    {
        public:
            using size;
            using push_back;
    };
    

    Dann kann man auch size und push_back aufrufen, ohne das Vererbt wurde.



  • Artchi schrieb:

    Daran ist nichts komisch. Wenn eine Klasse keinen virtuellen Dtor hat, ist sie nicht für Vererbung vorgesehen/bestimmt. Ist doch eine ganz einfache Definition?! Eine Klasse die nicht vererbar ist, hat ja trotzdem seine Daseinsberechtigung.

    Das habe ich nicht angezweifelt.
    Ich denke du meinst meine Phrase über die protected Sections...protected kommt ja wirklich nur bei Vererbung zum tragen?
    Oder war das evtl "Gewohnheit" des Entwicklers ... oder um sich die Option für später mal offen zu halten? Aber son "virtual" vorm destructor wäre ja dann auch kein Problem gewesen 😉

    Wenn ich hier jedoch diese "virtual"-Theorie mal runterprogrammiere mit dem g++ 4.0.3 interessiert ihn das wenig.

    Ich kann nicht-virtual methoden überschreiben, ohne dass die der Basisklasse stattdessen genutzt werden. Genauso werden auch beide Destruktoren nacheinander aufgerufen, trotz nicht-virtual.

    Was das Ganze noch komischer macht, warum das dann bei vector nicht geht 😉



  • In vielen Situationen funktioniert das mit der geerbten Klasse dann ganz gut, nur bei sowas nicht:

    vector<char*> *ptr = new myvector();
    delete ptr;
    

    Hier wird dann nur der Destruktor vom std-vector aufgerufen, weil er eben nicht virtual ist.

    Hast du denn noch zusätzliche Member-Variablen in deiner von vector erbenden Klasse?



  • Artchi! dein Code funktioniert nicht!



  • Bademeister schrieb:

    Artchi! dein Code funktioniert nicht!

    Den Template-Parameter wirst du ja wohl noch selber setzen können, oder? 🙄



  • jghj schrieb:

    Ich denke du meinst meine Phrase über die protected Sections...protected kommt ja wirklich nur bei Vererbung zum tragen?
    Oder war das evtl "Gewohnheit" des Entwicklers ... oder um sich die Option für später mal offen zu halten?

    Warum der Implementierer protected-Methoden verwendet, wird sein Geheimnis bleiben. Kannst ihn ja aber gerne fragen. Implementierungsdetails sind aber irrelevant. Entscheidend ist der Standard-Vector und wie er in der ISO-Norm definiert wurde. Da steht nichts von virtuellem Dtor und es werden meines Wissens auch nur public-Methoden dort beschrieben.

    Nur weil in der GCC-Vector protected Methoden benutzt werden, muß das nicht auf den Dinkumware-Vector zu treffen. Und es gibt noch mehr Implementierungen auf diesem Planeten.

    Wenn irgendwas unter GCC oder einem anderen Compiler unerwartet funktioniert, muß es auf einem anderen Compiler nicht auch so kommen. Es wäre natürlich wünschenswert wenn sich alle Implementierungen gleich verhalten. Ist aber nicht immer.

    Ich habe jedenfalls mal in einer meiner Basis-Klassen ausversehen virtual vergessen und es hat sich in einer späteren Situation ausgewirkt... ähnlich dem Beispiel von Badestrand. Vorher ist es mir nicht aufgefallen.



  • Artchi schrieb:

    Bademeister schrieb:

    Artchi! dein Code funktioniert nicht!

    Den Template-Parameter wirst du ja wohl noch selber setzen können, oder? 🙄

    Ja aber auch dann geht es nicht.



  • error C2873: 'size' : symbol cannot be used in a using-declaration
    error C2873: 'push_back' : symbol cannot be used in a using-declaration
    


  • Ohne code natürlich sehr aussagekräftig...
    Ich hab private-Vererbung in letzter Zeit auch des öfteren gebraucht

    typedef  std::vector< std::pair<Value,Value> > SolveContainer;
    class SolveModule : public Module , private  SolveContainer {
    
            public:
            using  SolveContainer::operator[];
            using  SolveContainer::size;
            using  SolveContainer::push_back;
    ...
    

    Schreibe deine Klasse analog dazu, dann sollte es gehen.



  • Ja nur weil ichs public nich erben kann wirds im private nicht mehr Sinn machen 😉

    Mit dem virtual verhält es sich doch so, dass der Destruktor bzw. Methoden, die durch eine Subklasse neu implementiert wurde, in jedem Fall augerufen wird.

    Unabhängig von einem Upcast.

    Wurde diese Klasse jedoch nicht ge"upcasted" so macht es doch garkeinen Unterschied ob virtual oder nicht, da das Objekt die Informationen über sich selbst ja kennt.

    Beim erstellen der Subklasse wird erst der Konstruktor der Basisklasse aufgerufen um das Objekt zu erzeugen, danach der eigene. Beim Zerstören des Objektes wird erst der eigene Destruktor aufgerufen und erst dann die aller Superklassen.

    Also warum laufe ich in Probleme wenn ich nie eine Zweideutigkeit (vorallem nicht in dem kleinen Beispiel) provoziere?

    Versteht mich bitte nicht falsch, ich will diese Lösung nicht auf Teufel komm raus durchsetzen. Aber ich würde schon gerne wissen, warum ich es anders machen sollte weil sich das nicht mit der Theorie (zumindest mit meiner ;)) deckt.



  • jghj schrieb:

    Ich möchte halt einfach den vector um ein paar für mich brauchbare Methoden ergänzen.

    Gibt es einen bestimmten Grund warum du auf Teufel komm raus eine Monsterklasse basteln willst, anstelle der offensichtlichen Variante:

    // arr.hpp
    typedef std::vector<char*> arr_t;
    
    void foo( arr_t const& self );
    void bar( arr_t&       self, /*...*/ );
    // ...
    


  • Bademeister schrieb:

    error C2873: 'size' : symbol cannot be used in a using-declaration
    error C2873: 'push_back' : symbol cannot be used in a using-declaration
    

    Sorry, war halt Pseudocode (genauso wie das fehlende Template), habe den Namensraum vergessen.



  • Ich will keine Monsterklasse bauen.

    Und ich denke, dass das Objektorientierte design schon seine Daseinsberechtigung hat. Auch wenn nicht möchte ich es in diesem realisieren und meine eigenen Prozeduren als Methoden und nicht als (globale) Funktionen realisieren.



  • jghj schrieb:

    Ja nur weil ichs public nich erben kann wirds im private nicht mehr Sinn machen 😉

    Es hat keiner gesagt, das es eine Vererbung ist. Es ist eine Lösungsvorschlag, den du anscheinend nicht akzeptieren willst. Mehr können wir aber auch nicht für dich tun.

    jghj schrieb:

    Beim erstellen der Subklasse wird erst der Konstruktor der Basisklasse aufgerufen um das Objekt zu erzeugen, danach der eigene. Beim Zerstören des Objektes wird erst der eigene Destruktor aufgerufen und erst dann die aller Superklassen.

    Also warum laufe ich in Probleme wenn ich nie eine Zweideutigkeit (vorallem nicht in dem kleinen Beispiel) provoziere?

    Versteht mich bitte nicht falsch, ich will diese Lösung nicht auf Teufel komm raus durchsetzen. Aber ich würde schon gerne wissen, warum ich es anders machen sollte weil sich das nicht mit der Theorie (zumindest mit meiner ;)) deckt.

    Hem, das Problem ist, das du der Definition ausweichen und nicht akzeptieren willst. Weißt du was du willst? Du willst eine Container-Klasse spezialisieren, obwohl das mit eben DIESEN Container-Klassen nicht möglich ist. Punkt. Warum ist die Banane krumm? Du wirst keine gerade Banane finden, nur weil dir die krummen nicht fallen. Eine Banane ist per Definition krumm. Punkt!

    Wenn du von vector erbst, wird dessen Dtor nicht immer aufgerufen und somit der Vector nicht korrekt aufgeräumt. Das wirst auch du nicht ändern können. Man kann jetzt fragen, warum Vector keinen virtuellen Dtor hat. Die Frage ist berechtigt, genauso wie mit der Banane. Aber nur wegen der Frage, wird sich die Definition nicht ändern.

    Wenn du Vererbbare Container haben willst, mußt du sie selber (neu) definieren oder im Netz nach entsprechenden suchen.



  • jghj schrieb:

    Ich will keine Monsterklasse bauen.

    Und ich denke, dass das Objektorientierte design schon seine Daseinsberechtigung hat. Auch wenn nicht möchte ich es in diesem realisieren und meine eigenen Prozeduren als Methoden und nicht als (globale) Funktionen realisieren.

    Die Standard-Bibliothek ist ja auch nicht komplett OO. ⚠ C++ ist eine Multiparadigmen-Sprache, und genau das gleiche spiegelt sich in der Stdlib wieder. Viele Typen (wie die Container oder Strings) machen sich lediglich die Möglichkeit des Datenverstecken zu nutze. Das es keine Vererbung gibt, kommt durch die Templates, die das ausgleichen. Und da spielen sicherlich Performance-Gründe eine wichtige Rolle! Es ist ein Paradigma das nunmal gewählt wurde und den C++-Standard ausmacht. Wenns einem nicht gefällt, kann man eine andere Library benutzen.

    Es gibt aber auch Std-Typen (wie die Streams) die vom kompletten OOD Gebrauch machen. Da wird sogar Mehrfachvererbung (iostream) eingesetzt, da hast du sogar das Extrem-OOD! Das ist ein anderes Paradigma, das auch in der Std-Lib existiert.

    Wenn man die Std-Lib benutzt, muß man sich auf diese Paradigmen und somit Design-Entscheidungen einlassen. Und wenn man Vector nicht korrekt vererben kann, dann muß man diese Design-Entscheidung akzeptieren oder man lässt diese Klassen links liegen.



  • Artchi schrieb:

    jghj schrieb:

    Ja nur weil ichs public nich erben kann wirds im private nicht mehr Sinn machen 😉

    Es hat keiner gesagt, das es eine Vererbung ist. Es ist eine Lösungsvorschlag, den du anscheinend nicht akzeptieren willst. Mehr können wir aber auch nicht für dich tun.

    class myvector : private std::vector
    {
        public:
            using size;
            using push_back;
    };
    

    Dieser code sagt mir, DASS es eine Vererbung ist.

    Es ist ein Lösungsvorschlag, der sagt, mach das Gleiche wie ich eh wollte nur definiere mir eben alles als private. Anschließend schalte ich die gebrauchten Methoden wieder frei für den public-Zugriff.

    Dieses bringt mir ja keinen Vorteil, da es genau das gleiche Vorgehen wie ich es bereits probiert habe widerspiegelt. (Um meine Aussage zu verifizieren habe ichs zusätzlich auch noch ausprobiert; das Praxisbeispiel bestätigt meine These)

    Und wie ich vorher versucht hab zu erklären möchte ich nicht den Standard ändern und will auch nicht unbedingt diese Lösung so durchziehen, da ich über die Komposition eine angebrachte Lösung habe (die mir aber nicht ganz so elegant wie die Vererbung erscheint).

    Die Frage, die für mich interessant ist: WARUM geht das nicht? Welche Codefloskel erlaubt mir die Vererbung, ändert aber die Funktionsweise der Superklasse.

    Nicht zuletzt interessiert mich das, weil es ja für mich selbst evtl auch mal sinnvoll sein kann, eine Klasse zu erstellen von der nicht geerbt werden darf.

    Als Argument fällt für mich jedoch der virtuelle Destruktor heraus, weil der ja bei dem Objekt selbst nicht zum tragen kommt und es schon nach der Initialisierung hängt.

    Dass C++ sehr vielseitig usw. ist und auf Altlasten aufbaut ist mir bewusst, jedoch weiß ich nicht warum ich statt einer Komposition oder anderen OO Vorgehensweisen auf einmal zurück zu C soll und mir Hilfsfunktionen anlegen soll?



  • Naja, private-Vererbung ist eigentlich keine Vererbung sondern eine Komposition.
    D.h. deine Klasse ist nacher kein STL-Container, sondern sie hat einen STL-Container!
    Durch den fehlenden virtuellen Destruktor handelst du dir in diesem Fall nur Probleme ein wenn du die Klasse z.B. über den Zeiger der Basisklasse löschen tust.
    Dann wird eben der falsche Destruktor aufgerufen. Darum vermeide das Problem indem du private-Vererbung benutzt und die Schnittstelle gezielt freigibst.



  • Okay das habe ich mitgenommen.

    Der Wert von size() nach dem Erstellen des Objektes ist aber immernoch sehr hoch und falsch... :|


  • Mod

    jghj schrieb:

    Ein Breakpoint nach beiden Objektinitialisierungen im Debugger mit folgenden Outputs von [Objekt].size();

    ar.size() = 3958981726
    vAr.size() = 0

    Ich hab zwar keine Ahnung, was dein Debugger hier anstellt, aber das Ganze ist ohnehin unsinnig. Die size-Memberfunktion muss in deinem Beispiel gar nicht instantiiert werden - der Versuch sie aufzurufen (ist das überhaupt das, was der Debugger dort tut?) daher sinnfrei. Das Verhalten eines Programms ist nicht für Debuggerausgaben definiert worden - wenn die "Größe" des Vektors gar nicht beobachtbar ist, ist die Analyse von Debuggerausgaben sinnlos, wenn du dich nicht von vornherein auf Compilerinterna festlegen willst.



  • jghj schrieb:

    Dass C++ sehr vielseitig usw. ist und auf Altlasten aufbaut ist mir bewusst, jedoch weiß ich nicht warum ich statt einer Komposition oder anderen OO Vorgehensweisen auf einmal zurück zu C soll und mir Hilfsfunktionen anlegen soll?

    Das ist keine Altlast und das hat *nichts* mit C zu tun. Es ist vielmehr ein anderes Paradigma. OOP ist auch *nicht* das Heilige Gral. Diese Hilfsfunktionen sind klares, elegantes und modernes algorithmenbasiertes Anwendungsdesign.


Anmelden zum Antworten