Oberklasse, Unterklasse und Pointerei



  • Hallo!

    Ich bin vollkommen am Verrückt werden. Was in Java richtig schön und wunderbar funktioniert, macht mich in C++ einfach fertig und auch nach stundenlanger Internet-Recherche bin ich kein Stück weiter.
    Zum Problem.
    Ich habe eine Oberklasse OBER, die abstrakt ist. Davon werden 2 Klassen abgeleitet UNTERA und UNTERB.
    Nun existiert eine "Oberklassenverwaltung" (eine Klasse, die eine map enthält, in dem Objekte vom Typ UNTERA und UNTERB gespeichert werden sollen)
    Und da fängt das Ganz schon an.
    Meine Oberklassenverwaltung hat eine Methode, mit der ein Objekt vom Typ UNTERA oder UNTERB zum vector hinzugefügt wird:

    class Verwaltung {
    public: 
    void addUNTER(OBER unterobjekt);
    
    private:
    std::map<OBER, int> unterobjekte;
    
    };
    
    (...)
    
    void Verwaltung::addUNTER(OBER unterobjekt) {
    insert(std::pair<OBER, int>(unterobjekt, 5));
    
    }
    

    (Sinnhaftigkeit spielt hier mal keine Rolle :D)

    Sooo, und das wäre es auch eigentlich schon. Denn schon bei der Deklaration der Methode addUNTER erhalte ich die Fehlermeldung, dass doch OBER eine abstrakte Klasse ist und ich deshalb kein Objekt davon erstellen kann. Gut, hab ichs also mit Pointern versucht. Da wollte dann die Map nicht mitspielen, da kein Verweis zu einem Verweis gespeichert werden kann. (so in etwa)

    Das größte Problem an der Sache ist, dass ich in meiner Hauptmethode 2 temporäre Variablen einmal vom Typ UNTERA und einmal vom Typ UNTERB habe, mit denen ich kurzzeitig arbeite, die dann in die Map über addUNTER KOPIERT werden sollen, damit sie dort vollwertig vorliegen und ich so lange mein Verwaltungsobjekt besteht darauf zugreifen kann.

    Ich denke es ist ziemlich konfus, liegt sicherlich auch daran, dass ich mitlerweile komplett verwirrt, dcoh hoffe ich ihr habt in etwa verstanden was ich meine.
    Und weil ichs vorhin erwähnt habe: in Java würde die Geschichte so funktionieren. (da ist Polymorphie irgendwie schöner ^^")

    Ich danke euch schon jetzt für eure Hilfe!
    Tek



  • (...)
    insert(std::pair<OBER, int>(unterobjekt, 5));
    (...)
    

    Muss natürlich:

    (...)
    unterobjekte.insert(std::pair<OBER, int>(unterobjekt, 5));
    (...)
    

    heißen. ^^"



  • Tek schrieb:

    Was in Java richtig schön und wunderbar funktioniert, macht mich in C++ einfach fertig und auch nach stundenlanger Internet-Recherche bin ich kein Stück weiter.

    Grundsätzlich: Polymorphie funktioniert nur mit Zeigern und Referenzen (Und eine Javareferenz entspricht im wesentlichen einem Zeiger). Wenn du unter C++ ein Objekt einer abgeleiteten Klasse einem Objekt einer Basisklasse zuweist, "schneidest" du es im wahrsten Sinne des Wortes ab.

    class Verwaltung
    {
      public: 
        void addUNTER(OBER * unterobjekt);
    
      private:
        std::map<OBER *, int> unterobjekte;
    };
    

    Der Harken hierbei ist, das die std::map (und alle anderen STL-Container) nicht Objekte hinter Zeigern "aufräumt", besser wären hier wohl die ptr-Container von Boost (z.B. ptr_map).



  • Tek schrieb:

    Was in Java richtig schön und wunderbar funktioniert, macht mich in C++ einfach fertig und auch nach stundenlanger Internet-Recherche bin ich kein Stück weiter.

    Falls Du es noch nicht wusstest: Java != C++
    Da steckt mehr Wahrheit drin, als Du wahrscheinlich denkst.

    Tek schrieb:

    Ich habe eine Oberklasse OBER, die abstrakt ist. Davon werden 2 Klassen abgeleitet UNTERA und UNTERB.
    [...]

    class Verwaltung {
    public: 
    void addUNTER(OBER unterobjekt);
    
    private:
    std::map<OBER, int> unterobjekte;
    
    };
    (...)
    

    [...]
    Und weil ichs vorhin erwähnt habe: in Java würde die Geschichte so funktionieren. (da ist Polymorphie irgendwie schöner ^^")

    🙄

    Du kennst anscheinend einen der wichtigsten Unterschiede zwischen C++ und Java nicht; nämlich dass Dir in C++ keine "implizite Indirektion" aufgezwungen wird. In Java kannst Du Objekte nie direkt halten, sondern nur über Java-Referenzen erreichen. In C++ ist eine Variable eines Klassen-Typs keine Referenz, sondern das Objekt selbst. Alles andere folgt daraus. Dementsprechend kannst Du auch keine Variable einer abstrakten Klasse anlegen sondern höchstens Zeiger und Referenzen mit diesen Typen bauen.



  • asc schrieb:

    ...besser wären hier wohl die ptr-Container von Boost (z.B. ptr_map).

    wobei ptr_map die Schlüssel selbst kopiert und nur die Werte über Zeiger speichert, soweit ich weiß.



  • krümelkacker schrieb:

    wobei ptr_map die Schlüssel selbst kopiert und nur die Werte über Zeiger speichert, soweit ich weiß.

    Stimmt, ich habe jetzt nicht darauf geachtet, das die Klasse als Schlüssel verwendet wird.



  • asc schrieb:

    Tek schrieb:

    Was in Java richtig schön und wunderbar funktioniert, macht mich in C++ einfach fertig und auch nach stundenlanger Internet-Recherche bin ich kein Stück weiter.

    Grundsätzlich: Polymorphie funktioniert nur mit Zeigern und Referenzen (Und eine Javareferenz entspricht im wesentlichen einem Zeiger). Wenn du unter C++ ein Objekt einer abgeleiteten Klasse einem Objekt einer Basisklasse zuweist, "schneidest" du es im wahrsten Sinne des Wortes ab.

    class Verwaltung
    {
      public: 
        void addUNTER(OBER * unterobjekt);
    
      private:
        std::map<OBER *, int> unterobjekte;
    };
    

    Der Harken hierbei ist, das die std::map (und alle anderen STL-Container) nicht Objekte hinter Zeigern "aufräumt", besser wären hier wohl die ptr-Container von Boost (z.B. ptr_map).

    Ok, so hatte ich meine Pointerei vorhin auch. Problem bei der Sache ist aber, dass ich dann nicht mit den temporären Objekten arbeiten kann, da ... ihr wisst ja Pointer und so. ^^ Folglich müsste ich in der addUNTER Methode eine Instanz der Referenz des übergebenen Pointers erstellen und diese in der Map speichern (die dann natürlich wieder zu std::map<OBER, int> werden muss) oder aber ich muss jegliches Unterobjekt als Variable behalten. Sehe ich das richtig? Gibts noch eine andere Methode bzw. habt ihr noch eine Idee? Wie kann ich bestmöglich aus dem übergebenen Pointer eine neue Instanz erzeugen (hierbei müsste ich ja auch wissen, ob es sich um ein UNTERA oder UNTERB handelt, richtig? Wenn ja: wie kann ich das unterscheiden? Wenn nein: wie sonst?) ^^

    Ich danke euch wahnsinnigst! 🙂

    @krümelkacker
    Die Ungleichheit ist mir schon klar, ich wollte mit dem Verweis nur auf das hindeuten, was ich eigentlich tun wollte. 😉

    Und der Unterschied war mir so noch nicht klar, danke dafür! 🙂



  • Ich verstehe deine Frage nun nicht. Wenn du die Pointer in der map speicherst gehe ich dann mal davon aus das du die dazugehörigen Objekte dynamisch erzeugst. Dadurch bist du selbst für die Zerstörung dieser verantwortlich. Ausser du verwendest Smart Pointer. Kannst ja mal nach dem Stichwort googlen und schauen was ein Smart Pointer ist.



  • Du solltest vielleicht nochmal mit einem C++ Grundlagenbuch anfangen, da es gewaltige Wissensprobleme (und Unterschiede zu Java) gibt.

    Tek schrieb:

    Problem bei der Sache ist aber, dass ich dann nicht mit den temporären Objekten arbeiten kann, da ... ihr wisst ja Pointer und so. ^^

    Du kommst von Java, und beschwerst dich darüber, das es nicht mit temporären Objekten geht? Java kennt nur Zeiger (auch wenn sie unter Java Referenz genannt werden, und sich Java um deren Freigabe kümmert) und alloziert diese ebenso wie in C++ mit new.

    In C++ gibt es aber 3 Varianten: Objekte, Referenzen (hat nichts mit den Java-Referenzen zu tun) und Zeiger (die am ehesten den Javareferenzen entsprechen).

    Tek schrieb:

    Folglich müsste ich in der addUNTER Methode eine Instanz der Referenz des übergebenen Pointers erstellen und diese in der Map speichern (die dann natürlich wieder zu std::map<OBER, int> werden muss)

    Die Map kann nicht vom Typ std::map<OBER, int> sein, unter gar keinen Umständen (suche mal nach dem Begriff "Slicing"). Sondern wenn überhaupt vom Typ std::map<OBER*, int>.

    Nochmal: Polymorphie kann ausschließlich mit Referenzen (nicht Java-Referenzen!) und Zeigern funktionieren, nicht wie du hier immer angibst mit Objekten. Und Referenzen kommen hier auch nicht infrage, da eine C++ Referenz nur ein Aliasname für eine Variable ist, und selbst keinen Wert hält (somit kann sie nicht verändert werden, und muss immer ein gültiges Gegenstück haben).

    Du wirst hier nicht um Zeiger, und die eigene Freigabe herum kommen.



  • asc schrieb:

    Du kommst von Java, und beschwerst dich darüber, das es nicht mit temporären Objekten geht? Java kennt nur Zeiger (auch wenn sie unter Java Referenz genannt werden, und sich Java um deren Freigabe kümmert) und alloziert diese ebenso wie in C++ mit new.

    In C++ gibt es aber 3 Varianten: Objekte, Referenzen (hat nichts mit den Java-Referenzen zu tun) und Zeiger (die am ehesten den Javareferenzen entsprechen).

    Nicht beschweren, eher verwirrt sein. ^^
    Aber ich danke dir, genau das hat mir extremst geholfen, da ich völlig auf dem falschen Dampfer war. Es funktioniert jetzt tip top und alles ist gut! 🙂
    Vielen, vielen Dank! 🙂


Anmelden zum Antworten