Auflistung von Instanzen
-
In meiner Klasse "Game" möchte ich soetwas wie eine Auflistung führen.
Es soll dynamisch ansprechbar sein, also wie ein Array.Was würde sich da empfehlen?
Es geht mir nur darum, dass ich in meinen Spielefunktionen nicht
LightHealthPotion potion; player.inventory.addItem(potion);sondern einfach
player.inventory.addItem(item[5]);Die Schreibweise [5] ist dabei nicht wichtig, hauptsache aufgezählt.
//EDIT:
Sorry, vergessen: In dem Array soll die Instanz einer Klasse gespeichert sein.
-
-
Wofür genau? So wie das aussieht möchtest du wohl eine ObjectFactory und damit die Items dynamisch anlegen. Sind deine Gegenstände von einer Basisklasse abgeleitet und wie sieht das inventory aus?
btw, öffentliche Membervariablen sind böse.
-
Ja, aber wenn ich die Instanz der zu kontrollierenden Klasse in private stecke, muss ich die Funktionen doppelt schreiben, da sie sonst nicht verfügbar sind.
Also die Klasse Game kontrolliert die Klasse Player, diese wiederrum kontrolliert die Klasse Inventory und diese dann letztendlich Slot/Item-Klassen.
Ich muss ja jetzt irgendwo eine Instanz aller Items anlegen, damit ich mit
game.player.inventory.addItem()
arbeiten kann.
Codeausschnitte:
Items.h
#ifndef _ITEMS_H_ #define _ITEMS_H_ //***INCLUDES***// #include <string> class Game; //***CLASS Slot***// class Slot { public: Slot(); virtual bool use() = 0; virtual bool isFull() = 0; virtual std::string getName() = 0; }; //***CLASS Empty***// class Empty : public Slot { public: Empty(); bool use(); bool isFull(); std::string getName(); private: std::string name; }; //***ITEM CLASSES***// class LightHealthPotion : public Slot { public: LightHealthPotion(); bool use(); bool isFull(); std::string getName(); private: std::string name; }; #endif _ITEMS_H_
-
Noch ein Nachtrag:
Inventory.h
class Inventory { public: Inventory(); bool addItem(Slot&); bool useItem(short); bool trashItem(short); Slot** ptrSlot; Empty* ptrEmptySlot; };Inventory.cpp
Inventory::Inventory() { ptrEmptySlot = new Empty; ptrSlot = new Slot*[(game.player.getSlots()+1)]; ptrSlot[0] = ptrEmptySlot; ptrSlot[1] = ptrEmptySlot; ptrSlot[2] = ptrEmptySlot; ptrSlot[3] = ptrEmptySlot; ptrSlot[4] = ptrEmptySlot; } bool Inventory::addItem(Slot &item) { for(int c = 0; c < (game.player.getSlots()+1) ; c++) { if(ptrSlot[c]->isFull()) continue; else { ptrSlot[c] = &item; return true; } } return false; } bool Inventory::trashItem(short slot) { if(ptrSlot[slot]->isFull()) { ptrSlot[slot] = ptrEmptySlot; return true; } else return false; } bool Inventory::useItem(short slot) { if(ptrSlot[slot]->use()) { ptrSlot[slot] = ptrEmptySlot; return true; } else return false; }
-
Hmm, eigentlich sind Items aber keine Slots (und das impliziert eine öffentliche Vererbung)!
class Item { // ... virtual void use () = 0; }; class Slot { public: Slot (std::auto_ptr<Item> p) : _item (p) {} Slot () : _item (0) {} void use () { if (_item != 0) _item->use (); } // ... Zuweisungen, set- und get-Methoden private: std::auto_ptr<Item> _item; };Inventory wäre dann einfach ein Vektor von Slots.
Ja, aber wenn ich die Instanz der zu kontrollierenden Klasse in private stecke, muss ich die Funktionen doppelt schreiben, da sie sonst nicht verfügbar sind.
Hmm, eigentlich nicht. So ist das Design auf jeden Fall sehr starr.
Ist es denn schlimmgame.getPlayer ("asdf").getInventory ().addItem ()zu schreiben? So würdest du dir mehr Möglichkeiten für Änderungen offen halten (und du kannst Threadsafe programmieren).
-
Also da kenn ich mich gar nicht mehr aus.
Warum funktioniert das eigentlich nicht:
for(int c = 0; c < (game.player.getSlots()+1); c++) ptrSlot[c] = ptrEmptySlot;und zwar anstatt:
ptrSlot[0] = ptrEmptySlot; ptrSlot[1] = ptrEmptySlot; ptrSlot[2] = ptrEmptySlot; ptrSlot[3] = ptrEmptySlot; ptrSlot[4] = ptrEmptySlot;game.player.getSlots() gibt 4 zurück.
-
Was heißt "geht nicht"?
-
Kritischer Abbruch.
-
1. Slot: Leer steht da noch, anstatt alle 5 durchzugehen.
...hat ein Problem festgestellt und muss beendet werden.
Offset: 0000259bAber ohne der Schleife passt alles.
-
Suspekt, aber mit "meiner" Variante leicht zu vermeiden ;).
-
Ich möchte keinen neuen Thread anfangen, habe hier noch eine Frage.
Habe ich es so richtig gemacht?(Öffentliche Membervariablen vermeide ich jetzt total!)
//In der .h class Game { public: Game(); void init(); Player getPlayer(); private: Player player; }; extern Game game; //In der .cpp Player Game::getPlayer() { return player; }Und noch was:
Ich dachte, extern bedeutet, man kann eine Variable von einer .cpp in die andere "kopieren".
In meiner Header steht das extern aber auch, und somit habe ich von überall Zugriff (NUR meine Game-Klasse).Kann mir jemand "extern" genauer erklären?
-
Auch wenn ich den Rückgabetyp von getPlayer als "const Player&" efinieren würde, sieht das ganz gut aus.
Kann mir jemand "extern" genauer erklären?
"extern" erklärt dem Compiler, daß es zwar eine Variable des angegebenen Typs gibt - aber nicht hier. Das heißt, der Compiler stellt in der aktuellen Übersetzungseinheit keinen Speicher für diese Variable bereit, sondern hinterlässt nur eine Notiz "hier benötige ist ein "Game" Objekt mit dem Namen "game"" - der Linker geht dann später alle Libraries durch und findet dort (hoffentlich) diese Variable.
(das entspricht dem reinen Prototypen bei einer Funktion)
-
Wobei noch zu erwähnen ist, daß globale Variablen böse sind
Also, laß lieber die Finger davon!Falls du den Spieler von Außerhalb der Game-Klasse manipulieren willst, sollte der Rückgabetyp übrigens "Player&" lauten.
-
Nur die Game-Klasse soll auf die Player-Klasse zugreifen können.
So, zunächst ist es wichtig, dass getPlayer() immer dieselbe Instanz zurückgibt!
Also player soll immer player sein, und nicht plötzlich eine neue Instanz!
Das ist doch solange der Fall, solange die Game-Klasse existiert, oder?
(Weil ja in der Game-Klasse Player player; steht)
Oder habe ich da was falsch verstanden?Nun zum extern.
Bei mir steht im HEADER ein extern. Aber im Header brauche ich die Instanz gar nicht.1. Möglichkeit:
Game.h mit extern Game game;
Game.cpp mit globalem Game game;
Und dann kann ich von überall auf game zugreifen, was ich auch möchte.2. Möglichkeit:
Game.h ohne extern Game game;
Game.cpp mit globalem Game game;
Und dann zB. in der main.cpp ein extern Game game;Beide Möglichkeiten scheinen mir gleich, wo ist jedoch der Unterschied/Vorteil/Nachteil usw..
MfG
-
Beide Möglichkeiten sind schlecht, weil sie wie gesagt globale Variablen verwenden. Das deutet meist auf einen Design-Fehler hin.
Was die dieselbe Instanz von Player betrifft, mußt du darauf achten, daß du von getPlayer keine Kopie, sondern eine Referenz zurückgeben läßt (bei der Kopie würdest du halt jedesmal einen neuen Player bekommen). Darum war deine ursprüngliche getPlayer Funktioni vermutlich nicht das, was du haben willst.
-
Danke, kannst du mir getPlayer() entsprechend umschreiben?
Ich bin gerade erst beim Kapitel Referenzen und Zeiger angekommen, habe mir noch nichts angeschaut.
So, also ich soll keine global definierte Instanzen verwenden?
Das heißt, ich lasse extern Game game; weg, und erstelle nur dort eine Instanz, wo ich sie benötige? (zB. in der main() Funktion)Bin für weitere Tipps dankbar

-
ceplusplus schrieb:
Danke, kannst du mir getPlayer() entsprechend umschreiben?
Ganz einfach - du mußt nur den Rückgabetyp der Methode von "Player" auf "Player&" (wenn der Aufrufende das Objekt ändern darf) bzw. "const Player&" (wenn er das Objekt nicht ändern darf) verändern.
So, also ich soll keine global definierte Instanzen verwenden?
Das heißt, ich lasse extern Game game; weg, und erstelle nur dort eine Instanz, wo ich sie benötige? (zB. in der main() Funktion)Ja - allerdings hat dann jede Instanz von Game ihr eigenes Player-Objekt.
(btw, eventuell könntest du auch mal nach "Singleton" googlen)
-
Die Funktion muß heißen:
Player& getPlayer()Die Implementierung kann so bleiben, d.h.:
Player& Game::getPlayer() { return player; }Zur Game-Klasse: Ja, du kannst zum Beispiel eine Instanz in der main Funktion anlegen. Das könnte zum Beispiel so aussehen:
int main() { Game theGame; theGame.play(); }Wesentlich mehr sollte in der main-Funktion ohnehin nicht drin stehen.
Dein ganzes Spiel kommt dann in Game::play hinein (beziehungsweise in davon aufgerufene Funktionen). Und da du in Game::play direkten Zugriff auf alles hast, was zu Game gehört (z.B. player), kannst du dir die getPlayer-Funktion dann gleich komplett sparen (ist nur ein Vorschlag, da gibt es sicher mehr als einen Weg das vernünftig zu designen).
-
Okay danke für die vielen Antworten und Hilfen!
(Singletons schaue ich mir lieber erst an, wenn ich mit meinem Buch fertig bin)
//EDIT:
Eins noch:
getPlayer() Kann ich ja nicht weglassen, wie soll ich sonst zugreifen?Zum Beispiel:
game.player.getName();
Geht dann nicht:
error C2248: "player" : Kein Zugriff auf private Element, dessen Deklaration in der Klasse "Game" erfolgte