Kleines Text rpg und schon erste schwierigkeiten
-
hardtolearncplusplus schrieb:
...
Du solltest dich wirklich erstmal um die Grundlagen kümmern. Einen Einstieg versuche ich mal zu geben:
a) Klasse vs. Objekt
Eine Klasse ist eine Schablone, ein Objekt die konkrete Ausprägung. Sprich eine Klasse Monster soll nur eine Schablone sein. Was haben deine Viecher...ähh Monster an Eigenschaften gemeinsam? So zum Beispiel wird jedes Monster wohl eine Bezeichnung und irgendwelche Kampfwerte haben (z.B. Stärke und Abwehr).Beispiel:
class Monster { private: std::string name; int staerke; int abwehr; //... };
Das bedeutet nicht das du jetzt separate Klassen für jedes Monster brauchst. Das "konkrete" Monster könnte beispielsweise ein Oger sein (name="oger", staerke=20, abwehr=10) oder eine Riesenschnecke (name="Riesenschnecke", staerke=10, abwehr=0). Dies alles sind aber Objekte, keine Klassen. Erst wenn du feststellst das du unterschiedliche Eigenschaften benötigst, brauchst du auch neue Klassen.
Monster oger; Monster riesenschnecke; // Zwar sind beide Variablen (oger und riesenschnecke) Monster, können aber // unterschiedliche Werte haben.
b) Methode
Was eine Funktion ist, solltest du verstehen. Eine Methode ist eine Funktion einer Klasse. Der unterschied zu einer Funktion besteht darin, das eine Methode Zugriff auf alle Elemente der zugehörigen Klasse hat (Wenn es sich um eine statische Methode handelt: nur auf die statischen Member der Klasse).Da nicht-statische Methoden immer zu einem konkreten Objekt gehören (das man in der Methode auch über den this->Zeiger verwenden kann [ist nur nötig bei Namenskonflikten, wie ich es absichtlich im nachfolgenden Beispiel bei der Methode SetName zeige]).
class Monster { private: std::string name; //... public: void SetName(std::string const & name) { // Der this-Zeiger verweist auf das entsprechende Objekt, dazu später mehr // Zuweisung des Parameter "name" zu der Membervariable "name" this->name = name; } std::string GetName() const { // this-Zeiger ist hier nicht nötig, da es hier keinen Konflikt // mit einer anderen Variable name gibt. return name; } //... }; int main() { Monster oger; Monster riesenschnecke; oger.SetName("Oger"); // Setzen des Namens über eine Methode, dies betrifft // aber nur "oger", nicht riesenschnecke riesenschnecke.SetName("Riesenschnecke"); std::cout << oger.GetName() << std::endl << riesenschnecke.GetName() << std::endl; // ... }
c) Konstruktor (& Destruktor)
Es ist gang und gebe das man Variablen initialisiert. Zu nichts anderen ist der Konstruktor. Der Konstruktor wird am Anfang einmalig pro erstellten Objekt aufgerufen, und das Gegenstück, der Destruktor wird einmalig pro erstellten Objekt aufgerufen wenn es zerstört wird.int main() { Monster oger; // Hier wird der Standardkonstruktor von der Klasse // Monster und dem Objekt oger aufgerufen. { Monster riesenschnecke; // Hier wird der Standardkonstruktor von der Klasse // Monster und dem Objekt riesenschnecke aufgerufen. } // Hier wird riesenschnecke destruiert } // Hier wird oger destruiert
Es kann mehr als einen Konstruktor geben (aber nur ein Destruktor, da es hier keine Aufrufparameter gibt). Als Standardkonstruktor wird ein Konstruktor bezeichnet der keine Parameter besitzt.
class Monster { private: std::string name; int staerke; int abwehr; public: Monster() // Standardkonstruktor, heißt wie Klasse : name(""), // <- Initialiserungsliste staerke(0), abwehr(0) { // <- Konstruktorrumpf } Monster( // Konstruktor mit Parametern std::string const & name, int staerke, int abwehr) : name(name), // Zuweisung des 1. Parameters zur ersten Membervariable staerke(staerke), abwehr(name) { } ~Monster() // Destruktor in unseren Fall leer... { } }; int main() { Monster oger("Oger", 20, 10); Monster riesenschnecke("Riesenschnecke", 10, 0); }
Bedenke wieder das oger und riesenschnecke unterschiedliche Objekte sind. Jetzt hätten wir beide Objekte den oben genannten Vorgaben entsprechend angelegt.
c.2) Konstruktor, Kopierkonstruktor, Zuweisungsoperator, Destruktor
Noch ein Stück tiefergehend: Objekte kann man anlegen und zerstören, soweit so gut. Doch ebenso lassen sie sich zuweisen und kopieren.int main() { Monster oger("Oger", 20, 10); // Konstrukor Monster oger2(oger); // Kopierkonstruktor Monster oger3 = oger; // Achtung: Ebenso Kopierkonstruktor oger2 = oger; // Zuweisungsoperator } // <-- Destruktor(en)
Automatisch legt der Compiler im Hintergrund auch alle davon an (sofern möglich), wobei der Standardkonstrukor nur generiert wird wenn kein anderer Konstruktor geschrieben wird. Und der automatische Kopierkonstruktor kopiert alle Werte 1:1 (Auchtung bei Zeigern, es wird der Wert des Zeigers, sprich die Adresse auf die er zeigt, und nicht das Objekt auf das er zeigt kopiert), der Zuweisungsoperator macht dies durch eine 1:1 Zuordnung.
Wenn etwas davon nicht gewünscht ist, kann man die entsprechende Methode private deklarieren und verzichtet auf die Definition.
Was der Kompiler automatisch generiert
class Klassenname { public: Klassenname(); // Konstruktor Klassenname(Klassenname const &); // Kopierkonstruktor Klassenname& operator=(Klassenname const &); // Zuweisungsoperator ~Klassenname(); // Destruktor }
Mehr tippe ich aber erstmal nicht...
cu André
-
hardtolearncplusplus schrieb:
Aber mit den Klassen ist ja alles schön und gut, aber ich verstehe das mit public, privat und mit den Methoden nicht ganz.
Also public bedeutet, dass der Anwender die Werte verändern kann?
Privat bedeutet, dass nur eine interne Aufforderung die Werte ändern kann?Private Variablen und Funktionen der Klasse können im Normalfall nur intern aufgerufen bzw. bearbeitet werden, während öffentliche auch von ausserhalb manipulierbar sind. Beispielsweise ist es oft sinnvoll, die Membervariablen privat zu machen und dann über Get- und Set-Funktionen (Schnittstellen) diese zu manipulieren.
class MeineKlasse { private: // privat: Variablen int x; float y; // y wird z.B. nur intern benötigt, deshalb keine Schnittstellen für y public: // öffentlich: Schnittstellen void SetX(int NewX); int GetX(); }; void MeineKlasse::SetX(int NewX) { x = NewX; } int MeineKlasse::GetX() { return x; } int main() { MeineKlasse A, B; // A und B sind Objekte oder Instanzen der Klasse A.x = 3; // geht nicht, weil x privat ist. Genauso y... A.SetX(3); // geht, weil die Funktion öffentlich (public) ist. int i = A.x; // geht auch nicht int i = A.GetX(); // geht wieder }
hardtolearncplusplus schrieb:
Methoden sind... ähm damit kann man ja ka.^^
Methoden nennt man die Funktionen, die im Zusammenhang mit Klassen bestimmte Aufgaben erfüllen. Meistens bezeichnet man damit Memberfunktionen, also die Funktionen, die in der Klasse deklariert sind. Im Beispiel vorher wären
GetX()
undSetX()
Methoden.hardtolearncplusplus schrieb:
Konstruktor weiß ich sowieso nicht. Obwohl ich mir das schon paarmal durchgelesen habe.
Der Konstruktor ist diejenige Memberfunktion, die beim Erstellen einer Instanz aufgerufen wird. Eine Klasse kann mehrere Konstruktoren haben. Diese können beim Aufruf Parameter übernehmen, um die internen Variablen auf einen Startwert zu setzen. Konstruktoren ohne Parameter nennt man Standardkonstruktoren. Normalerweise wird ein Standardkonstruktor automatisch vom Compiler erstellt, sobald du jedoch irgendeinen eigenen Konstruktor definierst, nicht mehr.
class MeineKlasse { private: int x; float y; public: MeineKlasse(int NewX = 0); // Konstruktor-Deklaration void SetX(int NewX); int GetX(); }; MeineKlasse::MeineKlasse(int NewX) // Konstruktor-Definition { x = NewX; y = 0.f; } int main() { MeineKlasse A(3); // Aufruf des Konstruktors mit Parameter 3 -> A.x ist jetzt 3 MeineKlasse B(); // parameterloser Aufruf -> Standardparameter 0 -> A.x ist 0 MeineKlasse C; // auch parameterlos, auch hier wird der Standardkonstruktor genommen.
-
Nexus schrieb:
//... MeineKlasse B(); // parameterloser Aufruf -> Standardparameter 0 -> A.x ist 0 //...
Ich glaube eher das er den B-Fall versucht als Funktionsaufruf zu werten...
-
asc schrieb:
Nexus schrieb:
//... MeineKlasse B(); // parameterloser Aufruf -> Standardparameter 0 -> A.x ist 0 //...
Ich glaube eher das er den B-Fall versucht als Funktionsaufruf zu werten...
fast. Es ist eine Funktionsdeklaration - hier passiert also schlicht und ergreifend gar nichts. Danke, C.