Objekte als Parameter und in multimaps
-
Ah, hatte mich gefragt, ob das typedef die deklaration übernimmt, aber mich dann zu blind auf deinen Code verlasse, Th..
Ich habe jetzt mal versucht, die Änderungen von Pumuckel einzuarbeiten, aber ich hänge (den Compilermeldungen nach zu urteilen) immernoch bei den Deklarationen der Listen mit den Pointern.
Da es wohl kaum Sinn mach, alles schnipselweise zu posten (am Ende lass ich was wichtiges aus) hier nochmal der gesamte Code.
#ifndef GALAXYMAP_HPP #define GALAXYMAP_HPP #include "Stellarobject.hpp" #include "Starsystem.hpp" #include "Coordinate.hpp" #include <map> #include <list> class Galaxymap { public: void add_item(Stellarobject *new_stellar, int new_x_pos, int new_y_pos); void remove_item(Stellarobject *curr_stellar, int x_pos, int y_pos); private: int x_size; int y_size; typedef std::map<Coordinate, list<Stellarobject*> > Galaxy_map; typedef Galaxy_map::value_type map_type; Galaxy_map Curr_map; }; #endif#include "Galaxymap.hpp" void Galaxymap::add_item(Stellarobject *new_stellar, int new_x_pos, int new_y_pos) { //empty field in map? if(Curr_map.find(Coordinate(new_x_pos,new_y_pos)) == Curr_map.end()) { //yes, so a new list has to be created and the new item has to be put in it list<Stellarobject*> new_list; new_list.push_back(new_stellar); Curr_map.insert(map_type(Coordinate(new_x_pos,new_y_pos), list<Stellarobject*>(new_list))); } else { //no, the item just has to be put into the existing list list<Stellarobject*> existing_list = Curr_map.find(Coordinate(new_x_pos, new_y_pos)); existing_list.push_back(new_stellar); } } void Galaxymap::remove_item(Stellarobject *curr_stellar, int x_pos, int y_pos) { //Is there a list at the coordinates? list<Stellarobject*>::iterator it = Curr_map.find(Coordinate(x_pos,y_pos)); if(it = Curr_map.end()) { //No, there is no list which means that there is nothing at all cout << "Failed to find object at position" << x_pos << " " << y_pos << "(Map empty)" << endl; } else { //There is a list, so we have to search it for the object list<Stellarobject*> temp_list = it; list<Stellarobject*>::iterator new_it; new_it = temp_list.find(curr_stellar); if(new_it == temp_list.end()) { cout << "Object wasn´t in the list" << endl; } else { delete *new_it; temp_list.erase(new_it); } } }Und das sagt der Compiler dazu:
Galaxymap.cpp: In member function
void Galaxymap::add_item(Stellarobject*, int, int)': Galaxymap.cpp:16: error: conversion from \std::_Rb_tree_iterator<std::pair<const Coordinate, std::list<Stellarobject*, std::allocator<Stellarobject*> > > >' to non-scalar type `std::list<Stellarobject*, std::allocator<Stellarobject*> >' requested
Galaxymap.cpp: In member functionvoid Galaxymap::remove_item(Stellarobject*, int, int)': Galaxymap.cpp:26: error: could not convert((&it) <unknown operator> ((const std::_Rb_tree_iterator<std::pair<const Coordinate, std::list<Stellarobject, std::allocator<Stellarobject*> > > >&)((const std::_Rb_tree_iterator<std::pair<const Coordinate, std::list<Stellarobject*, std::allocator<Stellarobject*> > > >)(&(((std::map<Coordinate, std::list<Stellarobject, std::allocator<Stellarobject*> >, std::less<Coordinate>, std::allocator<std::pair<const Coordinate, std::list<Stellarobject*, std::allocator<Stellarobject*> > > > >)((Galaxymap)this)) + 8u)->std::map<_Key, _Tp, _Compare, _Alloc>::end [with _Key = Coordinate, _Tp = std::list<Stellarobject*, std::allocator<Stellarobject*> >, _Compare = std::less<Coordinate>, _Alloc = std::allocator<std::pair<const Coordinate, std::list<Stellarobject*, std::allocator<Stellarobject*> > > >]()))))' tobool' Galaxymap.cpp:34: error: conversion from \std::_Rb_tree_iterator<std::pair<const Coordinate, std::list<Stellarobject*, std::allocator<Stellarobject*> > > >' to non-scalar type `std::list<Stellarobject*, std::allocator<Stellarobject*> >' requested
Galaxymap.cpp:38: error: 'class std::list<Stellarobject*, std::allocator<Stellarobject*> >' has no member named 'find'
Galaxymap.cpp:39: error: no match for 'operator==' in 'new_it == (&temp_list)->std::list<_Tp, _Alloc>::end [with _Tp = Stellarobject*, _Alloc = std::allocator<Stellarobject*>]()'
C:/Dev-Cpp/bin/../lib/gcc/mingw32/3.4.2/../../../../include/c++/3.4.2/bits/stl_tree.h:209: note: candidates are: bool std::_Rb_tree_iterator<_Tp>::operator==(const std::_Rb_tree_iterator<_Tp>&) const [with _Tp = std::pair<const Coordinate, std::list<Stellarobject*, std::allocator<Stellarobject*> > >]
Galaxymap.cpp:45: error: type `struct std::pair<const Coordinate, std::list<Stellarobject*, std::allocator<Stellarobject*> > >' argument given to `delete', expected pointer
Galaxymap.cpp:46: error: no matching function for call tostd::list<Stellarobject*, std::allocator<Stellarobject*> >::erase(std::\_Rb\_tree_iterator<std::pair<const Coordinate, std::list<Stellarobject*, std::allocator<Stellarobject*> > > >&)' C:/Dev-Cpp/bin/../lib/gcc/mingw32/3.4.2/../../../../include/c++/3.4.2/bits/list.tcc:96: note: candidates are: typename std::list<\_Tp, \_Alloc>::iterator std::list<\_Tp, \_Alloc>::erase(std::\_List\_iterator<\_Tp>) [with \_Tp = Stellarobject*, _Alloc = std::allocator<Stellarobject*>] C:/Dev-Cpp/bin/../lib/gcc/mingw32/3.4.2/../../../../include/c++/3.4.2/bits/stl\_list.h:894: note: std::\_List\_iterator<\_Tp> std::list<\_Tp, \_Alloc>::erase(std::\_List\_iterator<\_Tp>, std::\_List\_iterator<\_Tp>) [with \_Tp = Stellarobject*, \_Alloc = std::allocator<Stellarobject*>] C:/Dev-Cpp/bin/../lib/gcc/mingw32/3.4.2/../../../../include/c++/3.4.2/bits/stl\_function.h: In member functionbool std::less<_Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp = Coordinate]':
C:/Dev-Cpp/bin/../lib/gcc/mingw32/3.4.2/../../../../include/c++/3.4.2/bits/stl_tree.h:1102: instantiated fromtypename std::\_Rb\_tree<\_Key, \_Val, \_KeyOfValue, \_Compare, \_Alloc>::iterator std::\_Rb\_tree<\_Key, \_Val, \_KeyOfValue, \_Compare, \_Alloc>::find(const \_Key&) [with \_Key = Coordinate, \_Val = std::pair<const Coordinate, std::list<Stellarobject*, std::allocator<Stellarobject*> > >, \_KeyOfValue = std::\_Select1st<std::pair<const Coordinate, std::list<Stellarobject*, std::allocator<Stellarobject*> > > >, \_Compare = std::less<Coordinate>, \_Alloc = std::allocator<std::pair<const Coordinate, std::list<Stellarobject*, std::allocator<Stellarobject*> > > >]' C:/Dev-Cpp/bin/../lib/gcc/mingw32/3.4.2/../../../../include/c++/3.4.2/bits/stl\_map.h:498: instantiated fromtypename std::_Rb_tree<_Key, std::pair<const _Key, _Tp>, std::_Select1st<std::pair<const _Key, _Tp> >, _Compare, _Alloc>::iterator std::map<_Key, _Tp, _Compare, _Alloc>::find(const _Key&) [with _Key = Coordinate, _Tp = std::list<Stellarobject*, std::allocator<Stellarobject*> >, _Compare = std::less<Coordinate>, _Alloc = std::allocator<std::pair<const Coordinate, std::list<Stellarobject*, std::allocator<Stellarobject*> > > >]'
Galaxymap.cpp:6: instantiated from here
C:/Dev-Cpp/bin/../lib/gcc/mingw32/3.4.2/../../../../include/c++/3.4.2/bits/stl_function.h:227: error: no match for 'operator<' in '__x < __y'
-
Wie ich schon sagte, liegen alle C++ Standard Typen im Namensraum 'std'.
Am besten du erzeugst dir für jede Typ-Definition ein eigenes typedef:
typedef std::list<Stellarobject*> ObjectList; // sorry, hier hatte ich auch erst std:: vergessen (war natürlich nur ein Test, ob du es kapiert hast -) typedef std::map<Coordinate, ObjectList > Galaxy_map;Nun kannst du einfach
ObjectList new_list;schreiben.
Die restlichen Fehler muß du dann Zeile für Zeile durchgehen (oftmals werden dann Folgefehler angezeigt, die dann bei Eliminierung der ersten Fehler verschwinden).
Aber nur durch die Fehler versteht man C++ richtig (auch wenn die Fehlerbeschreibungen nicht gerade einfach sind - insbesondere bei den komplexen template-Definitionen).
P.S. sorry, hatte bei meinem ersten Posting die Variablen-Deklaration 'Map mmap' vergessen -)
-
Okay, ich bin meinen Code nochmal in Ruhe durchgegangen und habe ein paar Fehler gefunden.
Was ich aber immernoch nicht verstehe, ist wie ich aus meiner Map nun die Liste bzw. aus der Liste das konkrete Objekt extrahiere.
Mit find() erhalte ich ja nur einen Iterator, der auf den Key zeigt, an dem die Liste ist, oder einen Iterator, der auf das Ende der Map zeigt, wenn der Key nicht drin ist.Aber wie hole ich mit einem Iterator nun die Liste oder besser nen Zeiger auf die Liste?
Das hier funktioniert einfach nicht, aber was ist daran falsch?
Galaxy_map::iterator it = Curr_map.find(Coordinate(new_x_pos, new_y_pos)); Stellar_list existing_list = it;
-
Iteratoren kann man im Grunde wie Zeiger verwenden (* und -> Operator)
-
Könntest du das bitte etwas ausführen, d.h. mir sagen wie das in meinem konkreten Fall anzuwenden wäre?
Folgendes
Stellar_list existing_list = *it;habe ich schon vor einer Weile ausprobiert, und ich bekomme damit immernoch die Fehlermeldung
Galaxymap.cpp:17: error: conversion from `std::pair<const Coordinate, std::list<Stellarobject*, std::allocator<Stellarobject*> > >' to non-scalar type `std::list<Stellarobject*, std::allocator<Stellarobject*> >' requested
-
AAAARGL
Ich habs....
Stellar_list existing_list = it->second;Man muss natürlich aus dem Paar (Key,Value) den Value aussuchen...
-
Doch noch ne Frage:
pumuckl schrieb:
list<Stellarobject*>:: iterator it; bool delete_success = false; for (it = temp_list.begin(); it != temp_list.end(); ++it) { if(it == curr_object) { delete *it; temp_list.erase(it); delete_success = true; } }versuchs mal mit std::find, das liefert dir auch gleich den list::iterator, fuer den du dann erase() aufrufen kannst
Ist das nicht falsch? Nach der Beschreibung der STL hat doch nur die map eine find() Funktion, nicht aber die List, oder?
-
Er redet wohl von std::find, einer Funktion aus dem Header <algorythm>.
-
Ah, okay, hab ich gerade auch eingebaut, und der Compiler ist zufrieden damit.
Was mich aber immernoch verwundert, sind folgende Fehlermeldungen:
C:/Dev-Cpp/bin/../lib/gcc/mingw32/3.4.2/../../../../include/c++/3.4.2/bits/stl_function.h: In member function
bool std::less<\_Tp>::operator()(const \_Tp&, const \_Tp&) const [with _Tp = Coordinate]': C:/Dev-Cpp/bin/../lib/gcc/mingw32/3.4.2/../../../../include/c++/3.4.2/bits/stl\_tree.h:1102: instantiated fromtypename std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::find(const _Key&) [with _Key = Coordinate, _Val = std::pair<const Coordinate, std::list<Stellarobject*, std::allocator<Stellarobject*> > >, _KeyOfValue = std::_Select1st<std::pair<const Coordinate, std::list<Stellarobject*, std::allocator<Stellarobject*> > > >, _Compare = std::less<Coordinate>, _Alloc = std::allocator<std::pair<const Coordinate, std::list<Stellarobject*, std::allocator<Stellarobject*> > > >]'
C:/Dev-Cpp/bin/../lib/gcc/mingw32/3.4.2/../../../../include/c++/3.4.2/bits/stl_map.h:498: instantiated from `typename std::_Rb_tree<_Key, std::pair<const _Key, _Tp>, std::_Select1st<std::pair<const _Key, _Tp> >, _Compare, _Alloc>::iterator std::map<_Key, _Tp, _Compare, _Alloc>::find(const _Key&) [with _Key = Coordinate, _Tp = std::list<Stellarobject*, std::allocator<Stellarobject*> >, _Compare = std::less<Coordinate>, _Alloc = std::allocator<std::pair<const Coordinate, std::list<Stellarobject*, std::allocator<Stellarobject*> > > >]'
Galaxymap.cpp:6: instantiated from here
C:/Dev-Cpp/bin/../lib/gcc/mingw32/3.4.2/../../../../include/c++/3.4.2/bits/stl_function.h:227: error: no match for 'operator<' in '__x < __y'Hier Zeile 6 der Galaxymap.cpp:
if(Curr_map.find(Coordinate(new_x_pos,new_y_pos)) == Curr_map.end())Was bitte will mir der Compiler mit dem Salat sagen??
EDIT:
Habe hier im Forum was gefunden, bei nem Thread, wo jemand fast dasselbe vorhatte wie ich und auch denselben Fehler bekam. Als Lösung wurde folgendes gepostet:
.filmor schrieb:
Maps werden immer nach ihrem Schlüsseltyp sortiert. Damit das funktioniert, brauchst du ein Vergleichskriterium.
Standardmäßig ist der Comparetyp std::less<KeyType> und std::less ist mit dem <-Operator definiert.
Du hast also 3 Möglichkeiten, den Code zum Laufen zu bringen:
1. Du schreibst einen <-Operator für MyClass (ist aber nur sinnvoll, wenn ein solcher Vergleich tatsächlich logisch möglich ist)
2. Du spezialisierst das std::less-Template für deine Klasse
3. Du schreibst eine eigene Vergleichsfunktion (das Sinnvollste, wenn du nur in einem Kontext eine solche Map anlegst.Mein Problem ist, daß ich leider keine der drei möglichen Lösungen nachvollziehen kann und auch nicht weiss, welche davon nun für mich die einfachste/effektivste wäre.
Ich glaube zu verstehen, daß es darum geht, der STL beizubringen, wie sie meine Koordinaten nach Größe sortieren kann. Da wäre ja logisch einfach (entweder X oder Y Wert höher gewichten), aber wie und vor allem wo muss ich das implementieren.
Wäre für Codebeispiele sehr dankbar!
-
Sceletor schrieb:
.filmor schrieb:
Maps werden immer nach ihrem Schlüsseltyp sortiert. Damit das funktioniert, brauchst du ein Vergleichskriterium.
Standardmäßig ist der Comparetyp std::less<KeyType> und std::less ist mit dem <-Operator definiert.
Du hast also 3 Möglichkeiten, den Code zum Laufen zu bringen:
1. Du schreibst einen <-Operator für MyClass (ist aber nur sinnvoll, wenn ein solcher Vergleich tatsächlich logisch möglich ist)
2. Du spezialisierst das std::less-Template für deine Klasse
3. Du schreibst eine eigene Vergleichsfunktion (das Sinnvollste, wenn du nur in einem Kontext eine solche Map anlegst.Mein Problem ist, daß ich leider keine der drei möglichen Lösungen nachvollziehen kann und auch nicht weiss, welche davon nun für mich die einfachste/effektivste wäre.
Ich glaube zu verstehen, daß es darum geht, der STL beizubringen, wie sie meine Koordinaten nach Größe sortieren kann. Da wäre ja logisch einfach (entweder X oder Y Wert höher gewichten), aber wie und vor allem wo muss ich das implementieren.
Wäre für Codebeispiele sehr dankbar!
Genau darum gehts, um ein Vergleichskriterium. Auf welcher Ebene du dieses Kriterium implementierst, ist die Sache die du entscheiden musst, und das sind die obigen drei Punkte. Wie du vielleicht weißt, hat die std::map nicht nur den key_type und den value_type als Templateparameter, sondern (neben dem Allocator, den alle container haben) auch einen sogenannten Comparator, das ist ein Functor, der zwei key_types miteinander vergleicht. Default für den Comparator ist std::less.
Ich roll mal die Punkte von filmor von hinten auf: Punkt 3 bedeutet, einen eigenen Comparator zu schreiben. Das ist eine Klasse, die folgendes besitzen muss:
- einen Standardkonstruktor (kannder implizit durch den COmpiler generierte sein)
- einenbool operator()(const T&, const T&), der die zu vergleichenden Objekte streng ordnet. Beispiel hierfuer wärestruct CoordCompare { bool operator() (const Coordinate& a, const Coordinate& b) { //Wenn x-Koordinaten gleich sind ordne nach y-Koordinaten, sonst nach x-Koordinaten return (a.x==b.x) ? (a.y<b.y) : (a.x<b.x); } }; //benutzung dann wie folgt: std::map<Coordinate, Stellarobject*, CoordCompare>; //benutze CoordCompare fuer die Ordnung der CoordinatesZweite Möglichkeit ist, dem Compiler statt einem eigenen Comparator nur zu sagen, wie er std::less<> für Coordinaten zu verstehen hat, das waere dann eine Spezialisierung des templates:
namespace std { template<> struct less<Coordinate> { bool operator() (const Coordinate& a, const Coordinate& b) { //Wenn x-Koordinaten gleich sind ordne nach y-Koordinaten, sonst nach x-Koordinaten return (a.x==b.x) ? (a.y<b.y) : (a.x<b.x); } }; } //Nutzung: std::map<Coordinate, Stellarobject*>; //benutzt automatisch die Spezialisierung von std::less<Coordinate>Das sieht gleich aus, allerdings musst du jetzt bei Containern (und bei anderen Strukturen, die std::less<> nutzen) nicht mehr explizit den Comparator angeben sondern kannst dich darauf verlassen, dass der Compiler immer deine Spezialisierung findet.
Das allgemeinste ist Punkt 1, nämlich die Angabe eines operator< für deine Coordinate Klasse. Damit kannst du nichtnur Abfragen wie "if (coordiA < coordiB)" realisieren. std::less benutzt nämlich defaultmäßig (das heißt, wenn man nicht wie in Punkt 2 ne Spezialisierung angibt) den operator< (Die Implementierung besteht meist aus der kleinen Zeile "return a<b;"). Deshalb hat dein Compiler auch gemeckert, weil std::less den op< für Coordinate aufgerufen hat, dens aber nicht gibt. Die Implementierung ist simpel:
struct Coordinate { //... public: bool operator< (const Coordinate& other) const { //Wenn x-Koordinaten gleich sind ordne nach y-Koordinaten, sonst nach x-Koordinaten return (x==other.x) ? (y<other.y) : (x<other.x); } //... };(Bin mir grad nicht ganz sicher ob man op< auch außerhalb der Klasse mit zwei Argumenten implementieren kann und welche Version die Gurus da befürworten, aber so funktionierts auf jeden Fall)
Alle drei Varianten funktionieren für deine map gleich gut.
-
Also, ich habe den Comparator nun implementiert und er läuft auch prima, aber wenn ich nun was (erstmal ein Starsystem) in die Map stecken will, kommt:
matching function for call to `Galaxymap::add_item(Starsystem&, int&, int&)'
Galaxymap.hpp:15: note: candidates are: void Galaxymap::add_item(Stellarobject*, int, int)und das, obwohl Starsystem (wie von Th erklärt) von der abstrakten Klasse Stellarobject erbt.
Was muss ich an dem Code noch ändern?
battlefield.add_item(new_System, x_pos, y_pos);class Starsystem : public Stellarobject#ifndef STELLAROBJECT_HPP #define STELLAROBJECT_HPP class Stellarobject { }; #endifEDIT: Schon rausgefunden,
battlefield.add_item(&new_System, x_pos, y_pos);war die Lösung.
Wobei... Ist das richtig so? Und warum kann ich es nur als Referenz, nicht aber als Zeiger oder "ohne alles" (was wohl eine Kopie wäre dann) übergeben?
-
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..