Klasse dynamisch erstellen



  • Moin moin,
    ich habe da mal ein hoffentlich einfaches Problem.
    Ich habe in einem Spiel eine Klasse, welche einen Gegner darstellt.
    Dieser Gegner soll zu unterschiedlichen Zeiträumen und unterschiedlicher Anzahl zufällig auftauchen.
    Das heißt also, dass ich meine Klasse irgendwie dynamisch erstellen muss und dann auch individuell löschen / beenden muss.
    Im Moment rufe ich meine Klasse mit:

    TEnemy enemy();
    

    So kann ich ja nur einen Gegner erzeugen. da ich aber eben nicht weiß wie viele Gegner ich brauche, kann ich ja auch keinen Speicher bzw. die Klasse im Vorfeld erzeugen.
    Ich könnte natürlich folgendes schreiben:

    TEnemy enemy1();
    TEnemy enemy2();
    TEnemy enemy3();
    TEnemy enemy4();
    TEnemy enemy5();
    

    Hier muss ich aber im Vorfeld schon wissen wie viele Gegner ich maximal im Spiel haben möchte. Wie bekomme ich es aber hin, dass ich eine unbestimmte Anzahl Instanzen meiner Klasse erzeugen kann und diese dann auch individuell ansprechen kann?
    Sorry, hänge hier vollkommen.

    mfg
    Tobias



  • Wahrscheinlich möchtest Du einen std::vector<TEnemy> .

    btw.

    navysaebear schrieb:

    TEnemy enemy();
    

    Ist eine Funktionsdeklaration und keine Variablendefinition. Siehe Most vexing parse.



  • OK, ich habe mal ein kleines Testprogramm geschrieben und es klappt soweit. Was ich aber nicht verstehe ist, dass er mir den Destruktor zwischen drin aufruft.

    testklasse.h

    #ifndef TESTKLASSE_H
    #define TESTKLASSE_H
    
    #include <iostream>
    
    class TestKlasse
    {
    public:
        TestKlasse(int);
        ~TestKlasse();
        void PrintKlasseID();
    
    private:
        int KlasseID;
    };
    
    #endif // TESTKLASSE_H
    

    testklasse.cpp

    #include "testklasse.h"
    //#include <iostream>
    
    using namespace std;
    
    TestKlasse::TestKlasse(int KlasseNr)
    {
        KlasseID = KlasseNr;
        cout << "Klasse erzeugt : " << KlasseID << endl;
    }
    
    TestKlasse::~TestKlasse()
    {
        cout << "Klasse zerstört: " << KlasseID << endl;
    }
    
    void TestKlasse::PrintKlasseID()
    {
        cout << "Klasse ID      : " << KlasseID << endl;
    }
    

    main.cpp

    #include <iostream>
    #include <vector>
    #include "testklasse.h"
    
    using namespace std;
    
        vector<TestKlasse> TK;
    
    int main()
    {
        TK.push_back(11);
        TK.push_back(22);
        TK.push_back(33);
        TK[1].PrintKlasseID();
        TK.front().PrintKlasseID();
        TK.back().PrintKlasseID();
        return 0;
    }
    

    Als Ausgabe bekomme ich:

    Klasse erzeugt : 11
    Klasse zerstört: 11
    Klasse erzeugt : 22
    Klasse zerstört: 11
    Klasse zerstört: 22

    Klasse erzeugt : 33
    Klasse zerstört: 11
    Klasse zerstört: 22
    Klasse zerstört: 33

    Klasse ID : 22
    Klasse ID : 11
    Klasse ID : 33
    Klasse zerstört: 11
    Klasse zerstört: 22
    Klasse zerstört: 33

    Warum wird direkt nach dem Erzeugen der Destruktor aufgerufen?
    Am Ende meines Programms verstehe ich das ja. Warum aber zwischendurch und dann für jedes Element? 😕

    mfg
    Tobias



  • https://www.c-plusplus.net/forum/p2551856#2551856

    btw.
    Vergiss globale Variablen ( TK ).
    Warum das #include <iostream> im Header und nicht in der .cpp .
    Benutze Initialisierungslisten.
    Warum std::endl ? '\n' tuts auch.



  • btw.
    Vergiss globale Variablen (TK).
    Warum das #include <iostream> im Header und nicht in der .cpp.
    Benutze Initialisierungslisten.
    Warum std::endl? '\n' tuts auch.

    - Warum keine globalen Variablen? Was spricht dagegen?
    - #include <iostream> war mir gar nicht aufgefallen! Hatte ich vermutlich während meiner Teste vergessen wieder Rückgängig zu machen.
    - Wofür sollte ich in meinem Beispiel Initialisierungslisten nutzen?
    - std::endl vs '\n'? Ist ja doch reine Geschmackssache. Das Ergebnis sollte das Gleiche sein, oder?

    Den Link habe ich mir durchgelesen. Also wird mein Destruktor deswegen aufgerufen, weil ich mein Vector um einen erhöhe und die "Liste" umkopiert wird.
    Gibt es aber jetzt einen einfachen Weg um das zu verhindern? Ich meine wenn ich Aufräumcode in den Destruktor setzen möchte, könnte dies beim umkopieren zu komischen Ergebnissen führen.

    mfg
    Tobias



  • navyseabear schrieb:

    - Warum keine globalen Variablen? Was spricht dagegen?

    Fehleranfällig, kann von jeder Funktion geschrieben werden. Schlecht optimierbar. Variablen sollten immer so lokal wie möglich deklariert werden.

    navyseabear schrieb:

    - Wofür sollte ich in meinem Beispiel Initialisierungslisten nutzen?

    TestKlasse::TestKlasse(int KlasseNr)
    : KlasseID{ KlasseNr } // hier.
    {
        cout << "Klasse erzeugt : " << KlasseID << endl;
    }
    

    navyseabear schrieb:

    - std::endl vs '\n'? Ist ja doch reine Geschmackssache. Das Ergebnis sollte das Gleiche sein, oder?

    Nein, das ist nicht dasselbe. std::endl führt auch immer einen std::flush durch.

    navyseabear schrieb:

    Den Link habe ich mir durchgelesen. Also wird mein Destruktor deswegen aufgerufen, weil ich mein Vector um einen erhöhe und die "Liste" umkopiert wird.

    Ja. Wenn der Vector wächst passen seine Elemente eventuell nicht mehr in den dafür reservierten Speicherbereich --> Neuer, größerer Speicherbereich wird reserviert und die Objekte umkopiert und die alten zerstört.

    navyseabear schrieb:

    Gibt es aber jetzt einen einfachen Weg um das zu verhindern?

    std::vector<T>::reserve() , wenn die Anzahl der Elemente absehbar ist.

    navyseabear schrieb:

    Ich meine wenn ich Aufräumcode in den Destruktor setzen möchte, könnte dies beim umkopieren zu komischen Ergebnissen führen.

    Wenn Dein Konstruktor zu komischen Ergebnissen führt wenn eine Instanz deiner Klasse kopiert wird und das Original zerstört wird, ist er kaput.


Anmelden zum Antworten