Zur Laufzeit mehrere Instanzen erstellen



  • Hi, ich stehe hier vor einem Problem, was ich seit mehreren Monaten noch nicht lösen konnte, und zwar geht es darum, dass ich so eine Art "Level-Editor" programmiere. Wenn man im Menü auf "Spieler erstellen" geht, dann kann man den Spieler setzen (natürlich nur einmal möglich). Wenn ich jetzt aber Wände setzen will, dann möchte ich auch mehrere haben. Also das Programm ist WinAPI mit einer GUI, aber ich stelle den Code nur teilweise herein, weil er einfach zu lang ist:

    Globaler Gültigkeitsbereich:

    class CObjekt
    {
        private:
             ...
        public:
             ...
    };
    ...
    
    CObjekt *pSpieler = NULL;
    CObjekt *pWand = NULL;
    

    Beim erstellen vom Spieler:

    pSpieler = new CObjekt(hInst);
    

    Beim erstellen der Wand:

    pWand = new CObjekt(hInst);
    

    hInst ist hier einfach nur ein Parameter, dem ich den Konstruktor gebe, weil eine bestimmte Funktion die hInstance braucht.

    Das Problem, was mir auch sofort klar war:

    Ich überschreibe den Zeiger, wenn ich ein 2. Wandobjekt erstellen möchte. Wie kann ich es hinkriegen, ein 2. Objekt, 3., 4. ,usw. zur Laufzeit zu erstellen.

    Ich habe es mit nem Array versucht, aber dazu müsste ich den hInst Parameter entfernen, was leider nicht geht!

    mfg Nolf



  • Doch, für mehrere Instanzen benötigst du einen geeigneten Containertypen (z.B. std::vector, std::list oder auch (konstantgroße) Arrays).
    Und du kannst jedem Objekt trotzdem einen oder mehrere Parameter übergeben:

    std::vector<CObjekt> vec;
    
    vec.push_back(CObject(hInst));
    

    Wenn dein Objekt nicht kopierbar ist bzw. du Polymorphie (Klassen-Hierarchien)einsetzt, dann solltest du allerdings Zeiger verwenden:

    typedef std::vector<CObjekt *> ObjVec; // um weniger schreiben zu müssen
    ObjVec vec;
    
    vec.push_back(new CObject(hInst));
    
    // Freigabe der Objekte nicht vergessen (sobald sie nicht mehr benötigt werden)
    for(ObjVec::iterator it = vec.begin(); it != vec.end(); ++it)
      delete *it;
    

    Aber ich denke, dir fehlen generell noch ein paar Grundlagen (zumindestens, um gleich einen Level-Editor zu basteln).
    Arbeite erst einmal aus einen Tutorial oder Buch deiner Wahl mal die Standardcontainer durch (diese wirst du für fast jedes C++ Programm benötigen).



  • Ich hab ein Buch, und die generellen Grundlagen habe ich ja drauf, aber nicht diese fortgeschrittenen, wie diese Vektoren aus der STL.



  • Ich habe dann aber dazu mal eine Frage. Wenn ich jetzt das Objekt zeichnen will, tritt ein Fehler auf (ich sehe ihn nichtmal) und das Programm wird beendet.

    Hier mal der Code:

    case WM_PAINT:
    {
    ...
    	vec.at(AnzahlWandObjekte)->OnDraw(hdc, hbmWall);
    ...
    } break;
    

    Beim erstellen des Objektes:

    case IDM_SET_WALL:
    	pWand = new CObjekt(hInst);
    	vec.push_back(pWand);
    	AnzahlWandObjekte = vec.size();
    	break;
    

    Das gleiche tritt auch auf, wenn ich statt den ersten beiden Zeilen deinen Code benutze:

    vec.push_back(&CObjekt(hInst));
    

    Wie mache ich das richtig?



  • Bist du im Debugmode? Was wird dir denn beim Absturz für ne Meldung angezeigt???

    Wird höchst wahrscheinlich eine out_of_range-Exception fliegen. Denn vec.at(AnzahlWandObjekte) dürfte einfach falsch sein! Wenn der Vector z.B. 10 groß ist, kannst du nicht auf Index 10 zugreifen, weil immer bei 0 angefangen wird zu zählen!

    vec.at(AnzahlWandObjekte - 1) wäre schlauer. Wobei ich mich frage, warum du nicht einfach vec.at( vec.size() - 1) machst, wenn du eh immer nur das letzte Element haben willst?

    case WM_PAINT:
    {
    ...
        try
        {
             vec.at(AnzahlWandObjekte)->OnDraw(hdc, hbmWall);
        }
        catch(const std::out_of_range &e)
        {
            // hier den Fehler behandeln...
        }
    ...
    } break;
    

    Tip: http://www.kharchi.eu/wiki/doku.php?id=cpp:std:exception



  • Hmm ja daran lags wohl (out of range).
    Ich habe das Problem gerstern um 23 uhr noch selbst gelöst! 🙂
    Vielen Dank für eure hilfe (dieser Denkanstoß hat mir wirklich geholfen), denn auf Vektoren wäre ich so schnell nicht gekommen. Ich kann nämlich komischerweise nicht AnzahlWandObjekte benutzen, denn dann kommt der Fehler. Ich muss immer eine for-Schleife benutzen:

    (Beim WM_PAINT ist es ja klar, weil er ja alles Zeichnen soll):

    if(AnzahlObjekte>0)
    {
    	for(int i=0; i<AnzahlObjekte; i++)
    	vec.at(i)->OnDraw(hdc);
    }
    

    Aber bei normalen Aktionen, wo nur eins dieser Objekte benutzt wird, muss ich trotzdem eine for-Schleife benutzen:

    case WM_RBUTTONDOWN:
        if(AnzahlObjekte>0)
        {
            for(int i=0; i<AnzahlObjekte; i++)
            {
                if(vec.at(i)->CheckCollision(MouseX, MouseY))
                {
                    vec.pop_back();
                    AnzahlObjekte = vec.size();
                }
            }
        }
        break;
    

    mfg Nolf


Anmelden zum Antworten