Fragen zum dynamischen Erzeugen von Objekten



  • lugge86 schrieb:

    Vielen Dank dafür.
    Find ich auf den ersten Blick ungewohnt (hab geringe Java-Vorkenntnisse und eine gute Portion C). Dachte das würde sich wirklich nur auf die Sichtbarkeit von Membern beziehen.

    Ich lese mich zwar gerade in SmartPointer ein.
    Aber aus Interesse: Angenommen ich würde im Desktruktor meiner "Schule", so wie oben gezeigt, alle Grund- und Hauptschueler per Hand löschen indem ich durch die Map iteriere.

    Wie stelle ich bei diesem Vorgehen sicher, dass nicht nur der "Schueler"-Destruktor aufgerufen wird, sondern davor auch der jeweilige "Unterdekonstruktor"?

    Wie gesagt, du machst den Destruktor von Base virtuell. In meinem zitierten Beispiel oben stehts auch drin.

    In Java ist es genau anders herum als in C++. Du kannst erstmal jede Methode überschreiben, ausser du verbietest es per final. In C++ kannst du erstmal nix überschreiben (maximal nur überdecken), es sei denn du machst die entsprechende Methode virtual.



  • kleiner Troll schrieb:

    Wenn

    Base* b = new Derived();
    

    gehen würde, wäre private Vererbung völlig sinnlos, da du mit

    Base* b = new Derived();
    b->SomethingThatIsPublicInBase();
    

    den Zugriffsschutz den du durch private ja haben willst (sonst würdest du ja nicht private schreiben) jederzeit umgehen könntest, und sogar ganz versehentlich oft würdest.

    Du musst natürlich(*) casten...

    Base* b = (Base*)new Derived;
    b->SomethingThatIsPublicInBase();
    

    (*) natürlich wie in: "Natürlich ist's in C++ nicht so einfach, wie man denkt."



  • Muss ich? Das verwundert mich etwas, oder versteh ich dich grade falsch?

    class Foo {};
    class Bar : public Foo {};
    
    int main()
    {
       Foo* f = new Bar();
    }
    

    Kompiliert, wie ich auch erwarten würde, einwandfrei. (Bis auf eine Warnung das f nicht benutzt wird)

    @Lugge
    Das ist prinzipiell so ok. Es gibt noch ein paar Fallstricke, in C++ gibt's mit Vererbungs einige eigenarten, die zwar alle ihren Sinn haben aber überraschend sein können. Der virtuelle Destruktor ist wichtig (einfach in virtual ~Schueler();)



  • kleiner Troll schrieb:

    Muss ich? Das verwundert mich etwas, oder versteh ich dich grade falsch?

    Wohl schon.

    Musst Du natürlich nur, wenn Du an die public member einer privat(!) vererbten Klasse ranwillst. Bzw. einen Zeiger auf eine eigentlich "inaccessible base class" brauchst. Implizite Konvertierung zieht hier ja nicht - was ja der Aufhänger des Threads ist.
    :

    struct Base{
      void SomethingThatIsPublicInBase(){}
      virtual ~Base(){}
    };
    struct Derived : private Base{};
    
    int main(){
      Base* b = (Base*)new Derived;
      b->SomethingThatIsPublicInBase(); // !
      delete b;
    }
    

    Disclaimer: natürlich propagiere ich diesen Weg nicht! 🙂



  • kleiner Troll schrieb:

    Der virtuelle Destruktor ist wichtig (einfach in virtual ~Schueler();)

    Ja, habs mittlerweile auch umgeändert und es klappt.

    Jetzt werd ich das mal auf SmartPointer umstellen.
    Nur, was ich bisher herausgefunden habe: dieses oben genannte make_unique kommt erst in C++14 🙂



  • Dann hab ich dich tatsächlich falsch verstanden, du mich aber wohl auch 😉
    Es ging mir ja darum, warum es nicht ohne "tricks" geht das einfach so zuzuweisen.
    Mit dem guten alten "Mein lieber Compiler, halt die Klappe und tu was ich sage"-casts kann man das dann wieder schon machen, sollte man aber natürlich nicht. 🙂



  • lugge86 schrieb:

    kleiner Troll schrieb:

    Der virtuelle Destruktor ist wichtig (einfach in virtual ~Schueler();)

    Ja, habs mittlerweile auch umgeändert und es klappt.

    Jetzt werd ich das mal auf SmartPointer umstellen.
    Nur, was ich bisher herausgefunden habe: dieses oben genannte make_unique kommt erst in C++14 🙂

    Welchen Compiler nutzt du denn? Wenn du irgendwas C++11 fähiges nimmst, dann kannst du dir make_unique leicht nachbauen. Bei älteren Compilern ist das nicht mehr so trivial, aber da kannst du dir eine kleine spezialisierte Funktion schnell schreiben. oder du machst es auf herkömmliche Art und Weise und schiebst einen unique_ptr rein, den du on-the-fly oder vorher initialisierst.



  • Soo, ich hab leider noch was:

    Wie gesagt, ich sammle meine Grundschueler und Hauptschueler in einer map<Schueler*>

    Wenn ich durch die Map iteriere würde ich gerne feststellen, welchen Types denn der aktuelle Zeiger ist.
    Ich versuche es mit typeid:

    if (typeid(it->first) == typeid(Grundschueler*))
        cout << "Grundschueler" << endl;
    

    Leider schlägt der Vergleich nie an. An was liegt das?
    Kann ich überhaupt anhand des Zeigers aus der Map feststellen, welchen Typ das aktuelle Element hat?



  • lugge86 schrieb:

    Kann ich überhaupt anhand des Zeigers aus der Map feststellen, welchen Typ das aktuelle Element hat?

    Du kannst natürlich per dynamic_cast casten und prüfen, ob der Rückgabewert != NULL ist.

    Allerdings: wofür brauchst du das? Spezifisches Verhalten sollte mittels virtueller Methoden implementiert werden.


  • Mod

    Wenn ich durch die Map iteriere würde ich gerne feststellen, welchen Types denn der aktuelle Zeiger ist.

    Wenn du so etwas wissen möchtest, dann gehören die beiden Typen nicht in eine gemeinsame Liste. Benutz virtuelle Methoden.



  • lugge86 schrieb:

    if (typeid(it->first) == typeid(Grundschueler*))
        cout << "Grundschueler" << endl;
    

    Leider schlägt der Vergleich nie an. An was liegt das?
    Kann ich überhaupt anhand des Zeigers aus der Map feststellen, welchen Typ das aktuelle Element hat?

    Wenn du deine map nicht verändert hast(sie also noch eine map<string, schueler*> ist), dann ist das falsch.

    Du fragst, ob die typeid von einem String gleich der eines X-Schülers ist. Nein, niemals. Nimm nicht it->first, sondern it->second


Anmelden zum Antworten