Objekte als Parameter und in multimaps



  • Was ist 'new_system' denn?
    Anscheinend eine lokale Variable vom Type 'Starsystem'.
    Da du aber Zeiger auf Stellarobjekte in deiner Liste verwaltest, mußt du ein mit 'new' allokiertes Starsystem übergeben.
    Andernfalls wäre das Objekt ja nur temporär vorhanden (ab Blockende wäre der Speicher wieder überschrieben).
    Hier nun die korrekte Version:

    Starsystem *new_system = new Starsystem(...); // Parameter?
    battlefield.add_item(new_System, x_pos, y_pos);
    


  • Wie schon oben angedeutet musst du dich fuer dein Design fuer eine von zwei Varianten entscheiden, was die Speicherung angeht:
    entweder, du uebergibst deinem Container einen Zeiger auf ein bestehendes Objekt, oder das Objekt selbst. Wenn du ihm einen Zeiger uebergibst, sollte das kein Zeiger auf ein lokales Objekt sein, da sonst irgendwann ein Zeiger auf ein nichtmehr existierendes Objekt in deinem Container rumliegt. Daher musst du wie th schon sagt die Objekte mit new erzeugen (delete spaeter nicht vergessen!).
    Wenn du ihm das Objekt selbst zum Kopieren und Einfuegen uebergeben willst, gibt es zwei Probleme:
    erstens muesstest du fuer jede Klasse, von denen du Objekte in den Container legen willst, eine eigene Einfuegemethode schreiben. Denn sowas wie add_item(Stellarobject& newobject) funktioniert nicht, da dann nur der Basisklassenteil des Objekts kopiert wuerde und alle zusaetzlichen informationen verloren gehen (splicing). Zweitens kannst du in einen Container nicht Objekte verschiedenen Typs packen, also musst du trotzdem mit Pointern auf stellarobject arbeiten.
    Falls du (berechtigterweise) davor zurueckschreckst, die Objekte alle mit new und delete selbst verwalten zu muessen, gibts einen oft genutzten Ansatz: Du gibst der Klasse stellarobject die vieruelle methode Clone() mit, die das jeweilige Objekt dupliziert und einen Zeiger darauf zurueckgibt. Der add_item methode gibst du dann einen Zeiger auf das (moeglicherweise lokale) Objekt, die methode ruft davon Clone() auf, um einen Klon zu erstellen, der laenger als das lokale Objekt lebt. Das deleten dieses KLons muss dann der verwaltende Container uebernehmen.



  • EDIT:
    Hatte den Beitrag von Pumuckl nicht gesehen..
    Ich werde versuchen, den Ansatz von Th zu benutzen, d.h. mit Zeigern und new/delete arbeiten.
    Dann ist es doch ausreichend, nach dem Spiel einfach die Zeiger auf die Stellarobjects in der Map alle durchzugehen und die Objekte dazu zu deleten, oder?

    Davor hab ich aber noch ne andere Frage:
    Wie bekomme ich denn die Zeiger auf Stellarobjekte, nachdem ich sie aus der Liste wieder herausgeholt habe, wieder zu Instanzen von Starsystem, Blackhole etc. "zurückgebaut"?

    Muss ich da casten?

    Meine Funktion sieht jetzt erstmal so aus:

    //Get all the systems out of the map and render them
    void Game::render_starsystems()
    {
    	for (int n=0;n<field_width;n++)
    	{
    		for (int m=0;m<field_height;m++)
    		{
    			if(battlefield.check_pos(n,m)) // Do this only if mapfield is occupied
    			{
    				list<Stellarobject*> temp_list;
    				temp_list=battlefield.get_list(n,m); //Get the list out of occupied field
    
    				list<Stellarobject*>::iterator it = temp_list.begin(); //Iterate over the list and render the lists objects
    
    				while (it != temp_list.end())
    				{
    					it->render();
    					it++;
    				}
    			}
    		}
    	}
    }
    

    und der Compiler meckert, weil er render() nicht kennt (die ist ja auch nur in der Klasse Starsystem definiert, nicht in Stellarobject).



  • Du solltest dich evtl. erst mal ein wenig intensiver mit OOP beschäftigen, d.h. wie erstelle ich komplexere Klassen (-hierarchien) in C++.
    Ansonsten befürchte ich, daß dein Code dir irgendwann zu groß und komplex wird.

    Der beste Ansatz für das Rendern besteht dadrin, einfach eine virtuelle Methode 'render' in der Basisklasse zu definieren, welche dann von den abgeleiteten Klassen implementiert wird.

    Je nach Anzahl der abgeleiteten Objekte mußt du für dich entscheiden, ob du evtl. noch Zwischen-(Basis)klassen erstellst, welche Gemeinsamkeiten mehrerer Klassen implementieren.
    Der letzte Ausweg sollte sein, ein "dynamic-cast" zu benutzen, um zu schauen, um welches Stellarobjekt es sich handelt.
    Sobald du merkst, daß du an verschiedenen Stellen im Source "switches" benötigst, dann überleg dir, ob du nicht besser eine virtuelle Methode dafür bereitstellst.

    P.S.
    Deine Methode 'get_list' sollte besser eine Referenz auf die Liste zurückgeben, damit die Liste nicht beim Rendern immer kopiert wird (wenn auch nur die Zeiger):

    Stellar_list & temp_list = battlefield.get_list(n,m); // typedef benutzen!!!
    

    So langsam kriege ich selber wieder Lust, an einem Weltraumspiel zu arbeiten (vor Jahren hatte ich mal ein Spiel namens "Universe" entwickelt, bevor ich vorletztes Jahr bei Ascaron an "DarkStar One" mitprogrammiert hatte).



  • Wegen dem Beschäftigen mit OOP, insbesondere Klassenhierarchien:

    Gibts da was besonders sinnvolles im Web zu? Ich finde immerwieder Tonnen von Sachen zu den Basics (Variablen, Arrays, if,for, while...) aber zu komplexeren Themen hab ich noch nichts gesehen, also wäres nett, wenn du mir nen Link oder Buchtitel anempfehlen könntest (oder natürlich auch jeder andere hier).

    Und wofür soll ich in dem Code ein typedef benutzen?

    Um mal was zum Hintergrund der Sache zu erzählen:
    Ich arbeite jetzt seit nem guten Jahr immerwieder hobbymäßig an meinem Spiel, aber das Coden ist in der Vergangenheit stark in den Hintergrund getreten, da ich mich eher mit Zeichnen und Designdoc schreiben beschäftigt habe.



  • Hi Sceletor,
    also als Buch kann ich dir auf jeden Fall das Standard-Buch vom Erfinder von C++ empfehlen: B. Stroustrup - Die C++ Programmiersprache (4. Auflage).
    Das Buch ist zwar nicht ganz billig, aber es vermittelt einen sehr guten Überblick über alle Programmiertechniken als auch die Verwendung der C++ Standard Bbliothek (ursprünglich STL genannt).
    Und es gibt eigene Kapitel zum Design von C++ Programmen und weitere interessante Sachen (Templates, Exceptions).

    Den typedef habe ich extra benutzt, damit man nicht immer wieder die komplette template-Schreibweise hinschreiben muß.
    Außerdem hat es den Vorteil, daß du evtl. den verwendeten Datentypen leichter wechseln könntest (z.B. wenn du doch lieber std::vector statt std::list benutzen willst), nämlich nur an der einen Stelle in der Header-Datei.

    Mir hat es den Anschein, du programmierst einfach so drauf los und das kann, je größer das Programm wird, immer schwieriger werden, ein gutes und einheitliches Design zu verwenden.

    Du solltest zuerst damit anfangen, dir die Basisklassen und darauf aufbauenden Klassen genau zu überlegen, ehe du einzelne Methoden implementierst.
    Ein gutes Klassendesign führt meistens zu kleineren und überschaubareren Programmen.

    Ich will dir auf keinen Fall den Mut nehmen weiterzumachen, sondern dich einfach nur auf bestimmte Fallstricke bei C++ hinweisen.

    Und mit welcher GUI willst du denn die Sterne und schwarzen Löcher etc. zeichnen?

    Wenn du willst, kann ich dir ja bei deinem Projekt helfen.
    Ich selber entwickle auch Spiele (privat zwar keine 3D, aber trotzdem ansehbar, s.a. http://www.c-plusplus.net/forum/viewtopic-var-t-is-193889.html



  • Danke für die Empfehlung, werde mir das Buch definitiv mal ansehen 🙂

    Was meinen Programmierstil angeht hast du sicherlich recht, ich versuche aus einem Flickenteppich von Java-Kentnissen und C++ Buchschnipseln (und natürlich mit Google und diesem wunderbaren Forum) mir das zusammenzusuchen, was ich brauche. Sicherlich nicht der allerbeste Ansatz, aber ich bin einfach neugierig und wie du selber sagstest: Nur durch Fehler lernt man C++ richtig.

    Zeichnen tu ich meine Bildchen (einschließlich GUI) mit der SDL, weil die einerseits recht einfach zu benutzen ist und andererseits auch noch den Vorteil der Plattformunabhängigkeit hat.

    Dein Framework für Karten und Brettspiele habe ich mir angesehen, es erinnert mich sehr an das Spiel, was ich mit Komilitonen zusammen in Java für das Programmierpraktikum geschrieben habe (das war am Ende mit networking son 200 Klassen Monster).

    Aber ich hasse Java halt und will ein RICHTIGES Spiel programmieren (also mit Artwork und nem komplexen Gameplay), und deswegen geh ich den steinigen Weg und versuche C++ zu lernen, indem ich es anwende.

    Was das Layout der Klassen angeht... nun, wie ich weiter oben schon geschrieben habe ist mein Designdoc immernoch in der Entwicklung (bin so bei 20 Seiten im Moment), und ich denke, das Spiel wird eh beim programmieren "wachsen", als bis in Detail geplant und dann im Akkord genau nach Spezifikation umgesetzt das Licht der Welt zu erblicken.

    An dieser Stelle möchte ich auch bitten, von Warnungen und Gelächter abzusehen, ich weiss, daß das verdammt viel Arbeit wird und sicher nicht wenig Frustration, aber ich wills wenigstens versuchen.

    Was deine Hilfe angeht, die nehme ich natürlich gern in Anspruch, bitte schreib mich einfach im ICQ an (Numma steht im Profil), da bin ich die nächsten Tage wohl öfters. Wenn du kein ICQ nutzen solltest, schicke mir ne PM, dann können wir ja versuchen, ne andere Art der Kommunikation (Rauchzeichen?) zu finden 😃



  • Hi Sceletor,

    ICQ habe ich nicht, aber du kannst mir ja mal eine Mail schreiben (meine Mail-Adresse steht auf meiner Downloads-Seite).
    Ich könnte dir dann einige Tipps bzgl. deines Programmaufbaus (Klassenhierarchie und sinnvolle Trennung von GUI und Logik etc.) geben.

    P.S. Mit welchem Betriebssystem arbeitest du denn?
    Evtl. könntest du mir dann ja ein paar Hilfen zu SDL geben (bisher habe ich privat noch nicht mit einer 3D-Grafik-Library gearbeitet, sondern nur auf der Arbeit mit einer von der Firma erstellten DirectX-Wrapper-Library).



  • Kann mir jemand sagen, warum daß erasen und das spätere deleten der Liste so nicht klappt? Habe mir das mal mit den cout´s angesehen und der bleibt mit dem erase so 45 mal in der ersten liste und bricht dann ab...

    void Galaxymap::delete_starsystems()
    {
    	cout << "Trying to delete.." << endl;
    	int counter = 1;
    	Galaxy_map::iterator it = curr_map.begin();
    	while (it != curr_map.end())
    	{
    		cout << "mapentry" << endl;
            Stellar_list &temp_list = it->second;
    		Stellar_list::iterator iter = temp_list.begin();
    		while (iter != temp_list.end())
    		{
    			cout << "listentry" << endl;
    			delete (*iter);
    			//temp_list.erase(iter); HIER KNALLTS
    			iter++;
    			counter++;
    		}
    		//delete &temp_list; HIER AUCH
    
    		it++;
    	}
    	cout << "Deleted: " << counter << " Starsystems" << endl;
    }
    

    Vielleicht kann mir ja jemand da ein zwei Sätze zu sagen, daß erspart mir recht viel Recherche..



  • Hi Sceletor,
    wieder einige Probleme?

    Die Methode 'erase' gibt selber einen iterator zurück, den du weiterverwenden solltest:

    iter = temp_list.erase(iter);
    // ++iter; <-- nicht mehr benötigt
    

    Und die Liste brauchst du selber nicht löschen, da du ja die Liste selbst in der Map verwaltest (und keinen Zeiger darauf), d.h. nach der Iteration ist die Liste dann leer.

    Um die gesamte Map zu löschen, fehlt am Ende (nach der while-Schleife) noch:

    curr_map.clear();
    

    P.S. Hast du denn ein gutes STL-Tutorial (oder Buch)? Ich schick dir gleich mal einige Links (per E-mail).

    Edit:
    Mir ist gerade noch aufgefallen, daß man das Löscher der Liste noch besser programmieren kann:

    Stellar_list::iterator iter = temp_list.begin(); 
    while (iter != temp_list.end()) 
    { 
      delete (*iter); 
      iter++; 
    }
    temp_list.clear();
    

    Erst werden nur die Objekte 'deleted' und anschließend wird in einem Rutsch die Liste geleert (dies ist evtl. performanter, als einzelne Elemente zu löschen).

    Ich selber habe mir hierfür immer folgende template-Funktion geschrieben:

    template <typename T>
    void clear(T &c)
    {
      for(typename T::iterator it = c.begin(); it != c.end(); ++it)
        delete *it;
    
      c.clear();
    }
    

    Aufruf dann einfach mit

    clear(temp_list);
    

    Dieses Template funktioniert damit für alle STL-Container, in denen man Zeiger auf mit new angelegte Objekte hält.


Anmelden zum Antworten