Fragen zu nem Spielablauf....
-
Hi Leute,
habe mal wieder ne Frage, da ich zur Zeit sehr C++ interessiert bin :).
Zu meiner Frage...
Hatte vor ein Textbasiertes Rollenspiel zu schreiben... natürlich erstmal nur damit anzufangen

Habe bis jetzt mit Switch... case das Spielmenu erstellt, meine Frage wäre jetzt folgende:
wenn ich ein Menü erstellt habe, was so aussieht
cout << "Spielname"<< endl;
cout << "(N)eues Spiel"<< endl;
cout << "(C)harakter erstellen" << endl;Habe direkt zwei Fragen. Die erste wäre, wie kann ich erreichen dass wenn man "Neues Spiel" wählt, sich in ein weiteres menü verzweigt indem man einen Charakter erzeugen kann?
Und wenn ich jetzt auf Charakter erzeugen gehe, wie komm ich dann wieder ins menu zurück und kann mit dem erstellten Char ein neues Spiel beginnen ??
-
mano_zenn schrieb:
Habe direkt zwei Fragen. Die erste wäre, wie kann ich erreichen dass wenn man "Neues Spiel" wählt, sich in ein weiteres menü verzweigt indem man einen Charakter erzeugen kann?
Na, indem du es ausgibst
Und wenn ich jetzt auf Charakter erzeugen gehe, wie komm ich dann wieder ins menu zurück und kann mit dem erstellten Char ein neues Spiel beginnen ??
Schleifen sind dir bekannt?
-
So machen wir da mal nen F.A.Q-Antrag draus

template<typename T> class menu { public: template <typename object> class item { typedef void (object::*fnFunc)(); std::string m_caption; fnFunc m_func; object& m_obj; bool m_set; friend menu<object>; public: item(std::string const& caption, fnFunc func) : m_func(func), m_caption(caption), m_set(false) {} void operator()() { if (m_set)(m_obj.*m_func)(); } std::string const& get_title() const { return m_caption; } }; public: friend std::ostream& operator << (std::ostream& out, menu const& data) { for (std::size_t i(0); i < data.m_items.size(); ++i) out << "(" << i + 1 << ") " << data.m_items.at(i).get_title(); return out; } friend std::istream& operator >> (std::istream& in, menu& data) { std::size_t sel(0); do { if (!(in >> sel)) { in.setstate(std::failbit); return in; } } while (sel == 0 || sel >= data.m_items.size()); data.m_items.at(sel)(); return in; } public: menu(T& obj) : m_obj(obj) {} public: void push_back(item<T> const& item) { item.m_obj = m_obj; item.m_set = true; m_items.push_back(item); } private: std::vector<item<T>> m_items; T& m_obj; };... so ... hab es allerdings jetzt mal noch nicht getestet!
Benutzen:
struct game_menu { game_menu() : m_running(false) {} void on_start() { m_running = true; } void on_end() { m_running = false; } private: bool m_running; }; int main() { game_menu inst; menu<game_menu> menu_inst(inst); menu_inst.push_back(menu<game_menu>::item("Spiel starten", &game_menu::on_start)); menu_inst.push_back(menu<game_menu>::item("Spiel beenden", &game_menu::on_end)); while (true) { std::cout << menu_inst << std::endl; std::cin >> menu_inst; std::cout << "Spiel gestartet? " << inst.m_running << std::endl; } }soo ... das pass ich euch morgen mal noch an, damit es einfacher ist, aber das soll erstmal reichen

-
(D)Evil schrieb:
So machen wir da mal nen F.A.Q-Antrag draus

private: std::vector<item<T>> m_items;Sowas geht IMO erst mit C++09
std::vector<item<T>>
=>
std::vector<item<T> >

-
einen :kopfschüttel smilie:
-
Also ich kann fast noch garnix... deshalb meinte eher was anderes xD
Hier ist mein Code bis jetzt, bin bissl am rumspielen, sonst lern ich des nie...(D)Evil wäre echt cool, wenn du meinen code mal durchgehen könntest und die Fehler erklärst.
Und vielleicht noch paar Verbesserungsvorschläge ?!?!?
aber Achtung bin ganz frisch dabei 
#include <iostream>
#include <windows.h>using namespace std;
#pragma comment (lib, "winmm.lib")
//Funktionen
cout << "Auswahl: ";
cin >> Auswahl;switch (Auswahl)
{
case ('n'):
case ('N'):
{cout << "Bitte erstellen Sie einen Charakter" << endl;
NeuerChar ()
}break;
case ('o'):
case ('O'):
{//Weiß noch nicht

return 0;
}break;case ('i'):
case ('I'):
{
Credits ();}break;
case ('b'):
case ('B'):
{
cout << "Bis demnaechst in der Welt von ...." << endl;}break;
default :
{
cout << "Ungueltige Eingabe" << endl;}
}
}while (Auswahl != 'b' || Auswahl != 'B');
cout << "Bis zum naechsten Mal" << endl;
return 0;
}
// Funktionen Ich verstehe die Sache mit den Parametern irgendwie nicht ganz
// was da zurück gegeben wird usw.... 
// Credits...void Credits ()
{
cout << "????? Beta v1.0" << endl;
cout << "written by mano_zenn";
cout << "\n\n";}
//Neuen Charakter erstellen
//Verstehe aber wie gesagt die Rückgabewerte nicht ganz, aber auch so kommen
// bei diesem kleinen Code lauter Fehler... Wie kann ich dann diese Funktion //oben bei Neues Spiel aufrufen? der Spieler soll also nach der Ausgabe von //"Bitte erstellen Sie einen CHarakter" hier unten zu der Funktion kommen, um //einen zu erstellen....int NeuerChar () //?? Funktion für die Charaktererstellung ??
{
struct S_Chara
{
;
int Gesundheit = 150;
int Energie = 75;
char Name[30];
char Klasse[10];
};S_Chara Charakter;
cout << "Bitte waehlen Sie eine Klasse: \n\n";
cout << "(1)Krieger" << endl;
cout << "(2)Schurke" << endl;
cout << "(3)Magier" << endl;
cin.get (Charakter.Klasse, 9);cout << "Bitte geben Sie ihrem Helden einen Namen: ";
cin.get (Charakter.Name, 29);cout << endl;
cout << "Ihr Charakter:" << "\n";
cout << "Klasse: " << Charakter.Klasse << endl;
cout << "Name: " << Charakter.Name << endl;
cout << "Gesundheit: " << Gesundheit << endl;
cout << "Energie: " << Energie << "\n\n";}
Der Compiler sagt: Ungueltige Syntax fuer rein virtuelle Methode; '= 0' erforderlich
Gesundheit und Energie = nichtdeklarierter Bezeichner
-
mano_zenn schrieb:
...wäre echt cool, wenn du meinen code mal durchgehen könntest und die Fehler erklärst.
Und vielleicht noch paar Verbesserungsvorschläge ?!?!?Beginnen wir doch mal bei den absolut grundlegenden:
1. Setze Code bitte in Code-Tags (Das Symbol "C/C++" unter dem Editorfenster hilft dabei)
2. Rumspielen bringt nichts, wenn man sich noch nicht mal mit den wesentlichen Grundsätzen (Funktionen...) beschäftigt hat. Ich werde zwar Kommentieren, aber du solltest nochmal von vorne beginnen und dir die Grundlagen einzeln durchlesen, im kleinen Nachvollziehen, und dann dich nochmal damit beschäftigen.mano_zenn schrieb:
#include <iostream> #include <windows.h> using namespace std; #pragma comment (lib, "winmm.lib")Wenn du mit C++ anfängst hat aller Windowskram hier nichts, aber auch garnichts zu suchen. Zudem setzt du den eh nicht ein. Also auf das wesentliche reduzieren:
#include <iostream> // Für cin/cout... using namespace std; // std::cin ==> cin, std::cout ==> cout... // Niemals in Headern einsetzen, dort bitte ausschreiben!Dann benennst du etwas mit "Funktionen", aber du hast keine Funktion mit der du beginnst. Jedes C++ Programm beginnt mit einer "main" Funktion.
mano_zenn schrieb:
//Funktionen // <-- Hier Fehlt etwas sehr wichtiges cout << "Auswahl: "; cin >> Auswahl; // Was ist bitte Auswahl? Hund, Katze, Maus, Elefant? // Variablen müssen deklariert (und sollten in der Regel // initialisiert werden). // Nach deinem switch zu schätzen tippe ich mal auf einzelne // Buchstaben, sprich "char"Also beginnen wir doch einfach mal mit einer typischen main-Funktion:
int main() { // <-- Hier kommt dein Anfangscode rein... return 0; }Variablen:
Variablen dienen dazu Werte zwischenzuspeichern, du kannst nur mit Variablen arbeiten, die du vorher deklariert hast. Eine deklaration besteht aus dem folgenden:<typ> <variablenname> [= <initialisierungswert>];
typ: Was für Daten kann dein Variable aufnehmen?
variablenname: Name, über die du die Variable im Programmcode ansprichst.
initialisierungswert: Dies dient dazu die Variable mit einem sinnvollen Startwert zu versehen. In uninitialisierten Variablen kann irgendetwas stehen.Funktionen:
Um den Code möglichst übersichtlich zu halten, werde ich jetzt mal etwas in Funktionen trennen... Und dabei eine Funktion mal erklären:<rückgabewert> <funktionsname>([parameterliste])
rückgabewert: Der Wert, der von der Funktion als Ergebnis zurückgeliefert wird. Falls die Funktion nichts zurückliefern soll, ist "void" als Typ anzugeben.
funktionsname: Dies sollte klar sein, wie heißt deine Funktion?
parameterliste: Hier stehen Parameter die als Eingangsgröße für deine Funktion dienen.Nehmen wir einfach mal ein einfaches Beispiel, eine Funktion die den höheren von zwei Ganzzahlenwerten liefern soll:
int max(int a, int b) { if(a > b) // Wenn a größer b ist,... return a; // ... verlasse die Funktion und gebe a zurück return b; // Verlasse die Funktion und gebe b zurück }Der Rückgabewert ist also schlicht und ergreifend das Ergebnis. Falls du eine Funktion erst definierst (ausgestaltest) nachdem in der Reihenfolge schon die Funktion verwendet wird, musst du sie vorher deklarieren:
void ZeigeHauptmenu(); // Deklaration void Warten(); // Dies ist nur ein Beispiel um das schließen direkt aus // dem Compiler zu verhindern int main() { ZeigeHauptmenu(); // Aufruf Warten(); return 0; } void ZeigeHauptmenu() // Definition { // <-- Hier der Code für das Hauptmenü } void Warten() { // Für eine Erklärung siehe Konsolen-FAQ (Automatisches Schließen // verhindern) cin.clear(); cin.ignore(cin.rdbuf()->in_avail()); cin.get(); }So, jetzt wenden wir und erst einmal dem Hauptmenü zu. Wie du vorher schon gelesen hast, musst du Variablen vor der Verwendung deklarieren.
void ZeigeHauptmenu() // Definition { // Zuerst sollte man wohl ein Menü anzeigen cout << "*** Hauptmenü ***" << endl // endl = Zeilenumbruch << "n - Neuen Charakter anlegen" << endl // ...noch weitere Menüpunkte... << "i - Credits" << endl; char menuAuswahl; // Variablendeklaration cin >> menuAuswahl; // Nun die Menübehandlung // ... Hierzu gleich mehr // Return nicht nötig, da Rückgabewert void. Zum vorzeitigen // Beenden kann man aber "return;" schreiben. }So, nun haben wir schon einmal ein Grundgerüst. Das Menü machen wir wie von dir geplannt mit einem switch-Block. Nur haben wir hier ein Problem mit deinem while... Wo beginnt es? Was wollen wir wiederholen. ich entschließe mich zum anfang mal, immer das ganze Menü zu wiederholen und die Methode erst zu verlassen wenn b oder B gedrückt wurde.
void ZeigeHauptmenu() // Definition { char menuAuswahl; // Variablendeklaration { // <-- Begin der while-Schleife cout << "*** Hauptmenü ***" << endl // ...noch weitere Menüpunkte... << "i - Credits" << endl; cin >> menuAuswahl; // Ich habe mich mal entschieden immer in weitere // Funktionen zu verzweigen, da diese aber noch nicht // existieren, sind sie auskommentiert switch(menuAuswahl) { case 'n': case 'N': // NeuerCharakter(); break; // ... Weitere Punkte default: cout << "Ungueltige Eingabe" << endl; } // Solange wiederholen wie die MenuAuswahl weder 'b' noch 'B' ist } while(menuAuswahl!='b' && menuAuswahl!='B') // Alternativ: while(!(menuAuswahl=='b' || menuAuswahl=='B')) }Ich lass dir erstmal bis hier etwas kreativität und gehe mal noch auf den neuen Charakter ein wenig ein, ohne eine Lösung zu schreiben. Die Struktur muss nicht zwinged in der Methode stehen, ich würde sie in eine eigene Codeeinheit (Header .h / Source .cpp) trennen, um auch anderswo damit arbeiten zu können. Die Schreibweise mit "S_" davor entfinde ich persönlich als Unsitte, lieber nenne ich sie sprechend. Variablen benenne ich in der Regel klein, Strukturen/Klassen groß. Wenn du C++ lernst würde ich dir auch erst einmal von char-Arrays abraten, wenn du sie wirklich brauchst kannst du dich damit später noch befassen, ich nehme hier einfach mal die String-Klasse von C++ da die grade als Anfänger einfacher zu bedienen ist.
Ich trenne es erstmal in einen neuen Header, da die Struktur bisher keine große Logik hat, kann man es mit einem Header belassen, ich trenne aber dennoch um noch zu zeigen was man normalerweise in den Source macht:
// Charakter.h #if !defined(CHARACTER_HEADER) // <-- Inklude Guards, mehr später #define CHARACTER_HEADER #include <string> // Für std::string // Hier kein using, Gründe wirst du hier im Forum genug finden // Kurz: Du würdest das using damit global machen, was in der Regel mehr // Probleme als Vorteile mit sich bringt struct Charakter { // Normalerweise schreibe ich Variablen klein, öffentliche Member // aber groß... int Gesundheit; // Zuweisung ist hier nicht möglich int Energie; std::string Name; std::string Klasse; // Für initialisierungen benutzt man einen Konstruktor bei Klassen // Strukturen: Charakter() // Konstruktor heißt wie Struktur : Gesundheit(150), // Initialisierungsliste Energie(75), Name(), Klasse() { // Alternativ zur Initialisierungsliste hier die Zuweisung durchführen, // Initialisierungslisten sind aber meist die bessere Wahl. } // Willst du vielleicht nicht nur eine Standardvorbelegung haben, sondern // gleich richtig mit werten Füllen? Dann hier eine Alternative: // Zu const & gehe ich später noch ein Charakter(int gesundheit, int energie, const std::string& name, const std::string& klasse); // Ausgelagert für Beispiel in cpp }; #endif// Charakter.cpp #include "Charakter.h" using namespace std; // Hier using unproblematisch // Typische Auslagerung einer Methode anhand des zweiten Konstruktors Charakter::Charakter(int gesundheit, int energie, const string& name, const string& klasse) : Gesundheit(gesundheit), Energie(energie), Name(name), Klasse(klasse) { }So, um diese Struktur verwenden zu können musst du nun noch ein
#include "Charakter.h" in der Datei mit der main-Funktion machen (ich würde es direkt unter dem #include <iostream> schreiben.Include Guards:
Verhindert das eine Datei mehrfach herangezogen wird, genauere Erklärung findest du indem du im Forum suchst.Initialisierungen:
Strukturen können nicht dadurch initialisiert werden das du direkt hinter der Variable ein = <Wert> setzt. Du musst entweder über einen Konstruktor gehen oder diese einzeln Zuweisen (Die andere Alternative behalte ich für mich).const
Konstanter Wert, kann nicht geändert werden.const <typ>& <variablenname>
Konstante Referenz. So weit wirst du noch nicht sein, hier aber eine kurze erklärung: Du kannst Funktionen Werte, Referenzen oder Zeiger übergeben. Werte sind immer Kopien, was heißt das eine Änderung in der Funktion sich nicht nach außen auswirkt. Referenzen sind nur Aliasnamen, wenn du Referenzen einsetzt arbeitest du mit dem gleichen Wert (gleich ein Beispiel), Zeiger erkläre ich erstmal nicht, die Fragen werden noch früh genug kommen. Konstante Referenzen sind immer gut wenn einerseits der Wert nicht geändert werden soll, anderseits eine Kopie zu teuer (Performance, Speicher...) ist.Beispiele:
void foo1(int i) { i = 2; } void foo2(int& i) { i = 2; } void foo3(const int& i) { // i = 2; Zuweisung nicht möglich } int main() { int i = 4; foo1(i); // i Weiterhin 4, da mit Kopie gearbeitet wurde foo2(i); // i Nun 2, da eine Referenz verwendet wurde foo3(i); // Sonderfall: return in main ist implizit "return 0;" }Grundsätzlich ist es meistens sinnvoll eingebaute Datentypen wie int, char... als Wert, Objekte (wie std::string, Charakter...) als konstante Referenz zu übergeben, sofern man diese nicht verändern will.
Nun noch kurz zur Verwendung von strings und Konstruktoren:
// ... // Einmal Charakter über den Standardkonstruktor (ohne Parameter) // angelegt: Charakter neuerCharakter1; // Einmal Charakter über den Konstruktor mit Parametern // angelegt: Charakter neuerCharakter2(120, 100, "Raistlin Majere", "Magier"); // Stringbenutzung an ein paar Beispielen: // Zuweisungen neuerCharakter1.Name = "Horst"; neuerCharakter1.Klasse = "Krieger"; cin << neuerCharakter1.Name; // Direkte unterstützung in cin/cout // Und auch unterstützung einiger Operatoren... neuerCharakter1.Name += " von "; neuerCharakter1.Name = neuerCharakter1.Name + "der Gilde Alimania";So... das reicht erstmal um dich weiterforschen zu lassen.
cu André
-
wow ich bin sprachlos

Sowas nenn ich mal professionelle Hilfe!!! dank dir , werde es so bearbeiten.
Falls ich nochmal Fragen habe, komme ich gerne wieder auf dich zu!!
thx lg mano
-
Oh wei..
Wenn ich das mit den Funktionen mache, bekomme ich nur Fehler raus...
#include <iostream> #include <windows.h> using namespace std; //Funktionen void Credits (); void Zeigemenu (); void Warten (); int main () { Zeigemenu (); Warten (); return 0; } void Credits () { cout << "????? Beta v1.0" << endl; cout << "written by mano_zenn"; cout << "\n\n"; } void Zeigemenu () { char Auswahl; do { cout << "??????????????" << endl; cout << "--------------" << endl; cout << "(N)eues Spiel" << endl; cout << "(O)ptionen" << endl; cout << "(I)nfos" << endl; cout << "(B)eenden" << endl; cout << "Auswahl: "; cin >> Auswahl; switch (Auswahl) { case ('n'): case ('N'): { cout << "Bitte erstellen Sie einen Charakter" << endl; //NeuerChar () ;}break; case ('o'): case ('O'): { }break; case ('i'): case ('I'): { Credits (); }break; case ('b'): case ('B'): { // Hier soll er ja beenden, geht aber nicht die Schleife läuft immer weiter... cout << "Bis zum naechsten Mal" << endl; return 0; // Damit er beendet ?? kommt aber der Fehler void -Funktionen gibt hier einen Wert zurück... }break; default : { cout << "Ungueltige Eingabe" << endl; } } }while (Auswahl != 'b' || Auswahl != 'B'); cout << "Bis zum naechsten Mal" << endl; } void Warten() { // Für eine Erklärung siehe Konsolen-FAQ (Automatisches Schließen // verhindern) cin.clear(); cin.ignore(cin.rdbuf()->in_avail()); cin.get(); }
-
Was für Fehler denn genau?
$ g++ main.cpp main.cpp: In function »void Zeigemenu()«: main.cpp:88: Fehler: Return-Anweisung mit Wert in »void« zurückgebender FunktionErsetz mal das return 0 durch ein std::exit(0); bzw exit(0); und schreib am Anfang noch #include <cstdlib> dazu
EDIT://
Ein return; solle das auch erledigen und ist uU besserer Stil, frag mich nicht

-
Void -Funktion gibt einen Wert zurück...
siehe Deklaration von 'Zeigemenu'
Aber ich will ja erreichen, dass wenn man auf B drückt die Meldung kommt, bis zum nächsten Mal .... und er das Prog beendet.
Irgendwie geht das nicht, aber erst seitdem ich das Hauptmenu mit Funktionen aufrufe und nicht direkt den switch - case block in die main - Fuktion schreibe.
Die Schleife soll so lange laufen, bis der benutzer b oder B drückt ... dann soll er das Programm beenden.
geht das nicht mit return 0;
-
Schau dir mal an, ob das , was ich in meinen Beitrag editiert habe, hilft

-
Ne geht auch nicht^^
Mhm verstehe ich nicht. Also ich verstehe die Meldung schon...
Die Funktion ist ja void darf daher keinen Wert zurück geben... Aber wie soll das sonst gehen....
Wenn ich das in der main Funktion schreibe geht alles.... dann schreibe ich einfach hinter die while Schleife...
return 0; und er beendet ... aber hier geht das irgendwie nicht.
-
#include <iostream> #include <cstdlib> using namespace std; //Funktionen void Credits (); void Zeigemenu (); void Warten (); int main () { Zeigemenu (); Warten (); return 0; } void Credits () { cout << "????? Beta v1.0" << endl; cout << "written by mano_zenn"; cout << "\n\n"; } void Zeigemenu () { char Auswahl; do { cout << "??????????????" << endl; cout << "--------------" << endl; cout << "(N)eues Spiel" << endl; cout << "(O)ptionen" << endl; cout << "(I)nfos" << endl; cout << "(B)eenden" << endl; cout << "Auswahl: "; cin >> Auswahl; switch (Auswahl) { case ('n'): case ('N'): { cout << "Bitte erstellen Sie einen Charakter" << endl; //NeuerChar () ;}break; case ('o'): case ('O'): { }break; case ('i'): case ('I'): { Credits (); }break; case ('b'): case ('B'): { // Hier soll er ja beenden, geht aber nicht die Schleife läuft immer weiter... cout << "Bis zum naechsten Mal" << endl; exit( 0 ); // Damit er beendet ?? kommt aber der Fehler void -Funktionen gibt hier einen Wert zurück... }break; default : { cout << "Ungueltige Eingabe" << endl; } } }while (Auswahl != 'b' || Auswahl != 'B'); cout << "Bis zum naechsten Mal" << endl; } void Warten() { // Für eine Erklärung siehe Konsolen-FAQ (Automatisches Schließen // verhindern) cin.clear(); cin.ignore(cin.rdbuf()->in_avail()); cin.get(); }Compiliert bei mir genauso wie
#include <iostream> #include <cstdlib> using namespace std; //Funktionen void Credits (); void Zeigemenu (); void Warten (); int main () { Zeigemenu (); Warten (); return 0; } void Credits () { cout << "????? Beta v1.0" << endl; cout << "written by mano_zenn"; cout << "\n\n"; } void Zeigemenu () { char Auswahl; do { cout << "??????????????" << endl; cout << "--------------" << endl; cout << "(N)eues Spiel" << endl; cout << "(O)ptionen" << endl; cout << "(I)nfos" << endl; cout << "(B)eenden" << endl; cout << "Auswahl: "; cin >> Auswahl; switch (Auswahl) { case ('n'): case ('N'): { cout << "Bitte erstellen Sie einen Charakter" << endl; //NeuerChar () ;}break; case ('o'): case ('O'): { }break; case ('i'): case ('I'): { Credits (); }break; case ('b'): case ('B'): { // Hier soll er ja beenden, geht aber nicht die Schleife läuft immer weiter... cout << "Bis zum naechsten Mal" << endl; return; // Damit er beendet ?? kommt aber der Fehler void -Funktionen gibt hier einen Wert zurück... }break; default : { cout << "Ungueltige Eingabe" << endl; } } }while (Auswahl != 'b' || Auswahl != 'B'); cout << "Bis zum naechsten Mal" << endl; } void Warten() { // Für eine Erklärung siehe Konsolen-FAQ (Automatisches Schließen // verhindern) cin.clear(); cin.ignore(cin.rdbuf()->in_avail()); cin.get(); }Was hast du denn für neue Fehlermeldungen?
-
Ja so kompiliert er auch bei mir, also ohne return 0;
ich will aber das dass Programm beendet wird sobald b bzw. B gedrückt wird...
-
Bei mir beenden sich auch beide wenn ich auf B drücke ...
-
Verstehe ich nicht... bei mir läuft die Schleife einfach munter weiter^^
-
Hast du meins kopiert? 1:1?
-
Ok danke darth jetzt gehts.... Es lag an return 0;
einfach return; ... liegt wahrscheinlich daran das void keinen wert zurückgeben darf... weil die Funktion halt leer ist ^^
-
So hat bis jetzt alles geklappt, dass einzige was ich nicht ganz verstehe ist die Auslagerung von Dateien....
Mein Code sieht wie folgt aus.
Erst die Main datei!
#include <iostream> #include <Charakter.h> [e]using namespace std; //Funktionen void Credits (); void Zeigemenu (); void Warten (); int NeuerChar (); int main () { Zeigemenu (); Warten (); return 0; } void Credits () { cout << "????? Beta v0.1" << endl; cout << "written by mano_zenn"; cout << "\n\n"; } void Zeigemenu () { char Auswahl; do { cout << "??????????????" << endl; cout << "--------------" << endl; cout << "(N)eues Spiel" << endl; cout << "(O)ptionen" << endl; cout << "(I)nfos" << endl; cout << "(B)eenden\n\n" ; cout << "Auswahl: "; cin >> Auswahl; switch (Auswahl) { case ('n'): case ('N'): { cout << "Bitte erstellen Sie einen Charakter" << endl; //NeuerChar () Das soll eine neue Funktion werden die in der Funktion verzweigt ist... geht das ?? NeuerChar (); ;}break; case ('o'): case ('O'): { }break; case ('i'): case ('I'): { Credits (); }break; case ('b'): case ('B'): { // Hier soll er ja beenden, geht aber nicht die Schleife läuft immer weiter... cout << "Bis zum naechsten Mal" << endl; return; }break; default : { cout << "Ungueltige Eingabe" << endl; } } }while (Auswahl != 'b' || Auswahl != 'B'); cout << "Bis zum naechsten Mal" << endl; } void Warten() { // Für eine Erklärung siehe Konsolen-FAQ (Automatisches Schließen // verhindern) cin.clear(); cin.ignore(cin.rdbuf()->in_avail()); cin.get(); }Headerdatei Charakter.h!
#if !defined(CHARACTER_HEADER) // <-- Inklude Guards, mehr später #define CHARACTER_HEADER #include <string> // Für std::string struct Charakter { int Gesundheit; // Zuweisung ist hier nicht möglich int Energie; std::string Name; std::string Klasse; // Für initialisierungen benutzt man einen Konstruktor bei Klassen // Strukturen: Charakter() // Konstruktor heißt wie Struktur : Gesundheit(150), // Initialisierungsliste Energie(75), Name(), Klasse() ;} #endifund halt noch die Quellcodedatei Charakter.cpp
#include "Charakter.h" ;using namespace std; int NeuerChar (); { }Was ich nicht verstehe ist, in der Headerdatei ist jetzt die Struktur und auch die Intialisierung und alles. So die hab ich ja jetzt immer parat und kann sie in meine Projekte einbringen durch #inlude <Charakter.h>
Aber wie kann ich die Funktion jetzt ausführen... Muss ich die Funktion jetzt in Charakter.cpp schreiben ? Charakter.h ist ja nur die Struktur ich will aber, dass wenn man in der main auf Neues Spiel geht, dass dann die Funktion aufgerufen wird. Und man seinen Namen, die Klasse .. usw eingeben muss und es dann auch ausgeben wird.
Wie muss ich das jetzt in die Charakter.cpp schreiben, damit ich diese Funktion später in der main aufrufen kann ??
-
mano_zenn schrieb:
So hat bis jetzt alles geklappt, dass einzige was ich nicht ganz verstehe ist die Auslagerung von Dateien....
Ich weiß das es dir in den Fingern juckt, aber bitte lies dir mal ein Tutorial wirklich durch wo die Grundlagen beschrieben sind. Ich werde zwar nochmal antworten, aber dir fehlen einfach noch viele wichtige Grundlagen.
Auslagern von Dateien
Die Verteilung in mehrere Dateien hat zum einen den Sinn, den Code besser zu strukturieren, zum anderen um Codebestandteile an mehreren Stellen verwenden zu können.Dabei gibt es in C++ in der Regel eine Trennung in Header (meist .h) und Source (meist .cpp). Ausnahmen stellen Templatedefinitionen (hast du noch nicht, daher erstmal nur der vollständigkeit halber) dar, die man komplett im Header schreiben sollte.
Was gehört nun in den Header und was in den Source?
1. Grobe Untergliederung
Im Header sollte die Deklaration, im Source die Definition stehen. In der Regel sollte man eine grobe Richtlinie haben, die Wildwuchs ein bischen begrenzt und das ganze Überschaubar hält. Normalerweise tut man jeweils eine Klasse (oder komplexere Struktur) in eine eigene Codeeinheit (.h/.cpp) und zusammenhängende Funktionen tut man auch in überschaubarer Anzahl in einzelne Codeeinheiten. Dü könntest z.B. deine Menüfunktionen in eine solche Codeeinheit (z.B. menu.h...) packen.2. Eigentlicher Inhalt
a) Jeder Header sollte mit einem Includeguard geschützt werden. Dabei ist darauf zu achten das eindeutige Makronamen verwendet werden.
b) In der Sourcedatei ist immer der zugehörige Header zu inkludieren
c) Includes sollten soweit möglich erst in der Source-Datei gemacht werden, und nur wo nötig im Header (reduziert u.a. die Linkzeiten und vermeidet zyklische Abhängigkeiten)
d) Im Header sollte möglichst nur die Deklaration stehen3. Beispiel
Am einfachsten ist das Ausgliedern von Funktionen zu verstehen, da du etwas in der Art eh schon machst (Vorwärtsdeklaration von Funktionen):Header (menue.h)
#if !define(MENUE_HEADER) // alternativ: #ifndef MENUE_HEADER #define MENUE_HEADER // Deklaration so wie vorher in der main.cpp oder wie die bei dir heißt ;) void Credits(); void Zeigemenu(); void Warten(); int NeuerChar(); #endifSorce (menue.cpp)
#include "menue.h" // <-- weitere Includes void Credits() { // <-- Eigentlicher Code von der Funktion } // ...Bei Strukturen und Klassen ist es ähnlich, nur muss außerhalb der Klasse sichtbar sein welche Methoden (Funktionen der Struktur/Klasse) zu welcher Klasse gehören. Dies macht man dadurch in dem man den Klassennamen vor den Methodennamen schreibt und mittels Scopeoperator :: verbindet
Anmerkung: In C++ sind Strukturen und Klassen nahezu identisch, wundere dich nicht wenn ich ab und zu in den Begriff Klasse abrutsche... den Unterschied schreibe ich dir noch im P.S. dieses Beitrages als kleinen Vorgriff auf die Zukunft.
Initialisierungen gehören wenn möglich auch in den Source, du hast es nicht wie von mir geschrieben übernommen, sondern zerrissen ;P (Du hast aus zwei Teilbeispielen eins gemacht, und dieses dann als Kombination aus beiden zusammengesetzt, siehst du aber vielleicht im folgenden selbst)
Header (foo.h)
#if !define(FOO_HEADER) #define FOO_HEADER struct Foo { int A; int B; int GetA() const; // Beispiel für eine "normale" Funktion einer Klasse, einer "Methode" // const da es keinen Wert ändert Foo(); // Standardkonstruktor (spezielle Methode, keine Angabe Rückgabewert) Foo(int a, int b); // Konstruktor mit Parametern (spezielle Methode) }; #endifSorce (foo.cpp)
#include "foo.h" // Klassenname muss vor die Methode geschrieben werden int Foo::GetA() const { return A; // nicht-statische Methoden können direkt auf die Member zugreifen } // Konstruktoren können als einzige Initialisierungslisten besitzen Foo::Foo() : A(12), B(24) { } Foo::Foo(int a, int b) : A(a), B(b) { }So, nun gehen wir auf deine Problem ein:
mano_zenn schrieb:
Was ich nicht verstehe ist, in der Headerdatei ist jetzt die Struktur und auch die Intialisierung und alles. So die hab ich ja jetzt immer parat und kann sie in meine Projekte einbringen durch #inlude <Charakter.h>
Aber wie kann ich die Funktion jetzt ausführen... Muss ich die Funktion jetzt in Charakter.cpp schreiben ? Charakter.h ist ja nur die Struktur ich will aber, dass wenn man in der main auf Neues Spiel geht, dass dann die Funktion aufgerufen wird. Und man seinen Namen, die Klasse .. usw eingeben muss und es dann auch ausgeben wird.
Wie muss ich das jetzt in die Charakter.cpp schreiben, damit ich diese Funktion später in der main aufrufen kann ??
Ein Teil sollte dir am Beispiel klar werden. Da ich ungern fertige Lösungen präsentiere sondern immer gerne das mitdenken anrege, zeige ich dir mal wie man nun die Struktur Foo und deren Methoden verwenden kann:
main.cpp
#include "foo.h" int main() { // Als erstes legen wir ein Objekt der Klasse foo an: Foo a; // Was ist nun in der Zeile genau passiert? Es fand dank einer // Standardkonstruktordefinition nämlich etwas im Hintergrund statt // (Anmerkung: Entferne mal zum Test den Konstruktor ohne Parameter // aus Foo und prüfe mal was dann passiert: Richig, es lässt sich // kein Objekt so ("Foo a;") mehr anlegen. // // Also nochmal in aller Kürze: // Foo a; Legt ein Objekt der Struktur Foo an. Da hier keine weitere // Angabe erfolgt, wird die Struktur über den Standardkonstruktor // angelegt. Sprich: ohne es zu sehen wird Foo::Foo() aufgerufen! // Somit ist a.A 12 und a.B 24, wie in der Initialisierungsliste // angegeben // So, nun wollen wir mal eine Methode von Foo expliziet aufrufen int b = a.GetA(); // Dies ruft Foo::GetA() von der Instand a auf ;) // Nun zeigen wir mal den zweiten Konstruktor: Foo c(1,2); // Dieses mal wird c über den Konstruktor Foo::Foo(int a, int b) // angelegt... b = a.A; // Direkter zugriff auf den öffentlichen Member "A" von der // Instanz a }So... das erstmal wieder als Vorlage

Gerne konkrete Fragen aber bitte nicht blind abschreiben ohne es zu verstehen, lieber nochmal zu einen Thema fragen.
cu André
P.S: Keiner Vorgriff: Was ist der Unterschied zwischen einer Struktur und einer Klasse in C++?
Im wesentlichen sind Strukturen und Klassen identisch, mit Ausnahme der Sichtbarkeit. In Strukturen ist im Standardfall jeder Zugriff von außen erlaubt (sprich: du kannst auf alles von außen zugreifen wie z.B. im Beispiel über a.A, a.GetA()...) in Klassen ist erstmal der Zugriff verboten. Diese Sichtbarkeit kann man aber explizit für Teile ändern.