Objekte auf dem Heap sichern
-
Klappt irgendwie immer noch nicht , ich teste beim laden ja immer und lass mir einzelne daten der klasse ausgeben und da bekomm ich nur chineesische zeichen xD
also ich versuch ma ganz genau zu zeigen was ich habe
ich habe eine kLasse :
class sPlayer { public: std::string name; std::string Typ; int irgendwas; float money; };dann habe ich eine FUnktion in der die Datenzugewiesen werden :
void cWorld::enterworld(int _irgendwas , string _name , string _Typ) { sPlayer wPlayer; wPlayer.name= _name; wPlayer.irgendwas = _irgendwas; wPlayer.Typ = _Typ; wPlayer.money = 300.00; }jetzt möchte ich die Klasse sPlayer in der die Daten alle stehen sichern :
void cWorld::status_save(sPlayer *wPlayer) { ofstream nfout(file_name.c_str(), ios::binary ); nfout.write((char*)(wPlayer),sizeof(sPlayer)); nfout.close(); }und später wenn man das Programm zum Beispiel wieder startet laden :
void cWorld::LoadPlayer() { sPlayer wPlayer; ifstream nfin (dateiname.c_str(), ios::binary); //dateiname ist definiert nfin.read((char*)(&wPlayer), sizeof(sPlayer)); nfin.close();so wenn ich es jetzt ausgeben will kommen total komische Zeichen :
ausgeben tu ich es so :cout << wPlayer.Typ << endl; // Zum beipspielIch hoffe ihr versteht jetzt wie ich es machen will :
Ich vermute die fehler liegen beim speichern , laden , oder bei der übergabe des Pointer objekts an die funktion status_save .....
-
du hast mein posting schon gelesen oder ?
class sPlayer { public: std::string name; std::string Typ; int irgendwas; float money; };ein objekt dieser klasse kannst du NICHT per write() einfach so schreiben.
std::ostream& operator<<(std::ostream &out, const sPlayer &my_player) { /* wie du einen string speicherst bleibt dir ueberlassen, das ist nur ein beispiel wie du es machen koenntest */ out.write(my_player.name.c_str(), my_player.size() + 1); out.write(my_player.Typ.c_str(), my_player.size() + 1); out.write(reinterpret_cast<const char*>(&(my_player.irgendwas)), sizeof(my_player.irgendwas)); out.write(reinterpret_cast<const char*>(&(my_player.money)), sizeof(my_player.money)); return out; }sizeof(std::string) gibt dir schliesslich auch immer die gleiche groesse zurueck, egal wie lange der string auch sein mag.
auslesen musst es dann natuerlich auch wieder einzeln. kannst nichtauf einen schwung mit read() machen.
Meep Meep
-
Ohh haa jetzt hab ich sehr viele Compile errors :
nfin.read(wPlayer.name.c_str(), wPlayer.size() + 1);--> class sPlayer has no member named size
nfin.read(reinterpret_cast<const char*>(&(wPlayer.health)), sizeof(wPlayer.health));---> invaild conversion const char* to char*
nfin.read(reinterpret_cast<const char*>(&(wPlayer.health)), sizeof(wPlayer.health));-----> initializing argument 1 of ´std::basic_istream<_charT, _Traits>& std::basic_istream<_CharT,_traits>read(_ChartT*, std::streamsize) (with _CHarT =char, _Traits =std::char_traits<char>]
nfout.write(wPlayer.name.c_str(), wPlayer.size() + 1);----> request for member ´name in wPlayer´, which is of non-class type ´sPlayer*´
(das mit allen immer durch ...)Hat mich erst ma geschockt als so viele Fehler kamen xD .. liegt an der übergabe von (sPlayer *wPlayer) oder ? wie muss ich das denn richtig machen ?
-
hab auch falsch geschrieben.
sollte
std::ostream& operator<<(std::ostream &out, const sPlayer &my_player) { /* wie du einen string speicherst bleibt dir ueberlassen, das ist nur ein beispiel wie du es machen koenntest */ out.write(my_player.name.c_str(), my_player.name.size() + 1); out.write(my_player.Typ.c_str(), my_player.Typ.size() + 1); out.write(reinterpret_cast<const char*>(&(my_player.irgendwas)), sizeof(my_player.irgendwas)); out.write(reinterpret_cast<const char*>(&(my_player.money)), sizeof(my_player.money)); return out; }fuer den read brauchst du auch nor einen normalen char* - cast und keinen const char* - cast. den solltest nur beim write machen.
ich glaub dir fehlen einige grundlagen
Meep Meep
Meep Meep
-
mh...jetzt mekkert er noch über die strings beim einlesen
nfin.read(wPlayer.name.c_str(), wPlayer.name.size() + 1);--> invaild conversion const char* to char*
und über alle wirtes:
nfout.write(reinterpret_cast<const char*>(&(wPlayer.money)), sizeof(wPlayer.money));da sagt er : --> request for member ´money´ in wPlayer´, which is of non-class type ´sPlayer*´
Und das sagt er bei allen writes .. sonst hat er keine Fehler mehr .. außer das ich paar falsche aufrufe hab aber das bekomm ich sicherlich alleine hin ,..
ich weiß das mir paar Grundlagen fehlen ich bin noch am lernen von Ifstream
und danach möchte ich mich mit der Netzwerk Programmierung außeinander setzen .
Ich hab irgendwie voll Probleme das save and load in den Hauptquellcode einzubaun , weil als ich das ganze unabhänig geschrieben hatte, hat alles geklappt.
siehe hier :class sAccount //richtige Klasse anstatt Struct { public: string name; string HeroTyp; int health; int mana; int maxdmg; int mindmg; int defence; }; int main() { sAccount a1, a2; //zwei Instanzen werden erzeugt a1.name = "Toa"; a1.HeroTyp = "Mage"; a1.health = 10; a1.mana = 4; a1.maxdmg = 12; a1.mindmg = 2; a1.defence = 99; int eing; //menü zum auswählen ... cout <<"1 --> Speichern"<<"\n"; cout <<"2 --> Laden"<<"\n"; cout <<"ihre Wahl:"; cin >> eing; switch(eing) { case 1 : //Save !! { system("cls"); cout << "Waehle einen Accountnamen:" << flush; // unter welchem namen soll es gespeichert werden string file_name; cin >> file_name; CreateDirectory("Saves", NULL); //legt ordner save an file_name.insert(0, "Saves\\"); if (file_name.substr(file_name.length() - 4) != ".sav") //Hängt an den namen ein Sav file_name += ".sav"; ofstream nfout(file_name.c_str(), ios::binary ); //Den inhalt des files kann ein Mensch nicht lesen, i.e. binary, not text format. nfout.write((char*)(&a1),sizeof(a1)); //liest die klasse aus und schreibt sie in die Sav file nfout.close(); //schließt den Stream system("cls"); cout << "Dein Account wurde unter '" << file_name << "' gespeichert ..." << endl; } break; case 2 : //load !! system("cls"); string dateiname; DIR *dirHandle; // --- > liestet das verzeichniss Save auf struct dirent * dirEntry; dirHandle = opendir("Saves\\"); if (dirHandle) { while (0 != (dirEntry = readdir(dirHandle))) { puts(dirEntry->d_name); } closedir(dirHandle); } cout << "Gib den Namen deines Saves ein, den du laden willst:"; cin >> dateiname; dateiname += ".sav"; // wenn man namen ohne sav eingibt hängt das save dran system("Cls"); cout << "Load '" << dateiname << "' ...\n"; dateiname.insert(0, "Saves\\"); ifstream nfin (dateiname.c_str(), ios::binary); nfin.read((char*)(&a2), sizeof(a2)); //lad alles in die Klasse nfin.close(); //schließt den STream // Ausgabe cout << "Account as read from binary file " <<dateiname <<endl; cout << a2.name << endl; cout << a2.HeroTyp << endl; //gibt alles aus cout << a2.health << endl; cout << a2.mana << endl; cout << a2.maxdmg << endl; cout << a2.mindmg << endl; cout << a2.defence << endl; break; } }
-
Toa schrieb:
mh...jetzt mekkert er noch über die strings beim einlesen
nfin.read(wPlayer.name.c_str(), wPlayer.name.size() + 1);--> invaild conversion const char* to char*
naja die member-funktion c_str() liefert dir ja uach einen 'const char*' zurueck. da kannst du auch nichts reinschreiben. und wPlayer.name kann auch nicht erraten wie lange der string sein wird. das funktioniert so alles nicht. du solltest dich mal gruendlich mit den grundlagen auseinander setzen.
Toa schrieb:
nfout.write(reinterpret_cast<const char*>(&(wPlayer.money)), sizeof(wPlayer.money));da sagt er : --> request for member ´money´ in wPlayer´, which is of non-class type ´sPlayer*´
seh ich in deinem listing auch nicht wo das sein sollte.
vielleicht solltest du mal mit volkards kurs anfangen.
http://www.volkard.de/vcppkold/inhalt.html
ein gut geschriebener und leichtverstaendlicher kurs.Meep Meep
-
also das obere hab ich gelöst . war ja dumm von mir du hast ja ganz recht das c_str() gibt immer ein const char zurück und kann nicht modifiziert werden.
Aber das untere macht mir Probleme
nfout.write(reinterpret_cast<const char*>(&(wPlayer.money)), sizeof(wPlayer.money));---> request for member ´money´ in wPlayer´, which is of non-class type ´sPlayer*´
Kann es vielleicht daran liegen das ich der FUnktion die sachen so übergeben hab :
void cWorld::status_save(sPlayer *wPlayer) <-- also das der SternOperator falsch ist ?
-
Toa schrieb:
Kann es vielleicht daran liegen das ich der FUnktion die sachen so übergeben hab :
void cWorld::status_save(sPlayer *wPlayer) <-- also das der SternOperator falsch ist ?
ja. du uebergibst einen zeiger.
mach es per referenz oder du musst den zeiger dereferenzieren.Meep Meep
-
eine dereferenzierung würde dann so ausehen sPlayer&*wPlayer; oder ? .. ach man so kurz vor dem Ziel xD
-
ne so wPlayer->money. Besser wäre es aber wenn du keinen zeiger sondern eine referenz übergen würdest. also status_save(sPlayer& wPlayer). Beim Aufrufen der funktion dann ohne & übergeben.
-
Hab jetzt zwar keine Compile errors mehr aber es geht immer noch net *heul* ich verzeifel noch xD
Meine Klasse :
class sPlayer { public: std::string name; std::string HeroTyp; int health; int mana; int maxdmg; int mindmg; int defence; int level; int xp; float geld; };Die Klasse in der die Funktionen Deffiniert sind :
class cWorld { public: // Kirche - save /Delete Account / SpielZeit anzeige void Kirche(sPlayer *wPlayer); void LoadPlayer(); void status_save(sPlayer& wPlayer); };die FUnktion in der ich die Kirche aufrufe in der man Saven kann :
void cWorld::Greenvillage(sPlayer *wPlayer) { string eingabe; // Auswahl system("cls"); getline(20); colorcout('1',"Wohin moechten Sie?"); getline(20); cout << "-Kirche\n"; newline(1); // hehe :P cin >> eingabe; ..... Bla Bla ..: else if(eingabe == "-Kirche" ||eingabe == "-Kirche" ||eingabe == "kirche" ||eingabe == "Kirche") Kirche(wPlayer); //Kirche - speichern - löschen - spielzeit { }DIe Kirche an SIch in der man speichern kann:
void cWorld::Kirche(sPlayer *wPlayer) //Kirche - speichern - löschen - spielzeit { char menue; cout << "(s)pielstand speichern\n"; cout << "(a)ccounts löschen"; cout << "(g)esamte Spielzeit anzeigen"; cout << "____________________\n"; cout << "Bitte w\204hlen:\n"; cin >> menue; cout << "\a"; switch (menue) { case ('s'): { cWorld save; save.status_save(*wPlayer); // das ist nur WIchtig !!!! }break; case ('a'): { cout << "loeschen"; }break; case ('g'): { cout << "spielzeit"; //Muss noch gemacht werden ! }break; } }Das Saven:
void cWorld::status_save(sPlayer& wPlayer) { cout << "Waehle einen Accountnamen:" << flush; // unter welchem namen soll es gespeichert werden string file_name; cin >> file_name; CreateDirectory("Saves", NULL); //legt ordner save an file_name.insert(0, "Saves\\"); if (file_name.substr(file_name.length() - 4) != ".sav") //Hängt an den namen ein Sav file_name += ".sav"; ofstream nfout(file_name.c_str(), ios::binary ); //Den inhalt des files kann ein Mensch nicht lesen, i.e. binary, not text format. nfout.write(wPlayer.name.c_str(), wPlayer.name.size() + 1); nfout.write(wPlayer.HeroTyp.c_str(), wPlayer.HeroTyp.size() + 1); //liest strings ein nfout.write(reinterpret_cast<const char*>(&(wPlayer.health)), sizeof(wPlayer.health)); //liest alles einzeln ein nfout.write(reinterpret_cast<const char*>(&(wPlayer.mana)), sizeof(wPlayer.mana)); nfout.write(reinterpret_cast<const char*>(&(wPlayer.maxdmg)), sizeof(wPlayer.maxdmg)); nfout.write(reinterpret_cast<const char*>(&(wPlayer.mindmg)), sizeof(wPlayer.mindmg)); nfout.write(reinterpret_cast<const char*>(&(wPlayer.defence)), sizeof(wPlayer.defence)); nfout.write(reinterpret_cast<const char*>(&(wPlayer.level)), sizeof(wPlayer.level)); nfout.write(reinterpret_cast<const char*>(&(wPlayer.xp)), sizeof(wPlayer.xp)); nfout.write(reinterpret_cast<const char*>(&(wPlayer.geld)), sizeof(wPlayer.geld)); nfout.close(); //schließt den Stream system("cls"); cout << "Dein Account wurde unter '" << file_name << "' gespeichert ...\n\n" ; system("pause"); }Und Später dann das laden und ausgeben :
void cWorld::LoadPlayer() { sPlayer wPlayer; string dateiname; DIR *dirHandle; // --- > liestet das verzeichniss Save auf struct dirent * dirEntry; dirHandle = opendir("Saves\\"); if (dirHandle) { while (0 != (dirEntry = readdir(dirHandle))) { puts(dirEntry->d_name); } closedir(dirHandle); } cout << "Gib den Namen deines Saves ein, den du laden willst:"; cin >> dateiname; dateiname += ".sav"; // wenn man namen ohne sav eingibt hängt das save dran system("Cls"); cout << "Load '" << dateiname << "' ...\n"; dateiname.insert(0, "Saves\\"); ifstream nfin (dateiname.c_str(), ios::binary); nfin.read(reinterpret_cast< char*>(&(wPlayer.name)), sizeof(wPlayer.name)); nfin.read(reinterpret_cast< char*>(&(wPlayer.HeroTyp)), sizeof(wPlayer.HeroTyp)); nfin.read(reinterpret_cast< char*>(&(wPlayer.health)), sizeof(wPlayer.health)); //liest alles einzeln ein nfin.read(reinterpret_cast< char*>(&(wPlayer.mana)), sizeof(wPlayer.mana)); nfin.read(reinterpret_cast< char*>(&(wPlayer.maxdmg)), sizeof(wPlayer.maxdmg)); nfin.read(reinterpret_cast< char*>(&(wPlayer.mindmg)), sizeof(wPlayer.mindmg)); nfin.read(reinterpret_cast< char*>(&(wPlayer.defence)), sizeof(wPlayer.defence)); nfin.read(reinterpret_cast< char*>(&(wPlayer.level)), sizeof(wPlayer.level)); nfin.read(reinterpret_cast< char*>(&(wPlayer.xp)), sizeof(wPlayer.xp)); nfin.read(reinterpret_cast< char*>(&(wPlayer.geld)), sizeof(wPlayer.geld)); nfin.close(); //schließt den STream cout << "Account as read from binary file " <<dateiname <<endl; system("pause"); cout << wPlayer.name << endl; system("pause"); cout << wPlayer.HeroTyp << endl; system("pause"); cout << wPlayer.health << endl; system("pause"); cout << wPlayer.mana << endl; system("pause"); cout << wPlayer.maxdmg << endl; system("pause"); cout << wPlayer.mindmg << endl; system("pause"); cout << wPlayer.defence << endl; system("pause"); cout << wPlayer.xp << endl; system("pause"); cout << wPlayer.geld << endl; system("pause"); }...SO jetzt hab ich echt alles gepostet , ich bin am rande der verzeiflung ..Seit Stunden und Tagen verusche ich es einzubaun und es geht einfach nicht
MFG TOa
-
Hallo zusammen,
bietet boost nicht Mittel zur Serialisierung?
Grüße Martin
-
http://www.boost.org/libs/serialization/doc/index.html
sollte man da einfach mal einsetzen
-
nfin.read(reinterpret_cast< char*>(&(wPlayer.name)), sizeof(wPlayer.name));So geht das nicht. Man kann nicht einfach einen std::string* nach char* casten.
Mach's z.B. so:
std::vector<char> buf(1024); nfin.read(&(buf[0]), buf.size()); wPlayer.name.assign(buf.begin(), buf.end());Damit würden allerdings nur Strings bis 1024 Zeichen eingelesen werden können, außerdem hab ich's jetzt nicht getestet.
-
Am besten schreibst du vor jeden String noch einmal die Länge des strings. Denn mein Beispiel würde jetzt nur mit Strings gehen, die immer 1024 Zeichen lang sind.
-
bitte keine tipps mehr über unsichere cast-orgien - gerade anfänger haben damit arge probleme
das boost zeug sollte wesentlich praktischer und einfacher zu verwenden sein
-
das problem beim einlesen seiner strings ist, das er nicht weiß wie lange sie sind. also koennte man beim speichern der strings noch die laenge mitgeben. dann hat man schon ein problem weniger.
inline void WriteStringToStream(std::ostream &out, const std::string &str) { std::size_t len = str.size(); out.write(reinterpret_cast<const char*>(&len), sizeof(len)); out.write(str.c_str(), len); // '\0' brauchen wir nicht mehr, weil wir die laenge speichern }zum auslesen kann man dann folgendes machen:
void ReadStringFromStream(std::istream &in, std::string &str) { std::size_t len; in.read(reinterpret_cast<char*>(&len), sizeof(len)); char *buffer = new char[len]; in.read(buffer, len); str.assign(buffer, len); delete[] buffer; }
-
schaut euch ma die ausgabe an :
http://www.imagehack.eu/uploads/b7f20d91fe.jpg
die ersten beiden Sachen stimmen noch ich hieß Ujih und mein Typ war Warrior aber die Zahlen dann nicht mehr .. also die sTrings werden richtig gespeichert und ausgegeben nur die zahlen haben Probleme
... wisst ihr warum ? die Lösung ist so nahe ^^PS :
sieht jetzt so aus :
ifstream nfin (dateiname.c_str(), ios::binary); vector<char> buf(1024); nfin.read(&(buf[0]), buf.size()); wPlayer.name.assign(buf.begin(), buf.end()); nfin.read(reinterpret_cast< char*>(&(wPlayer.HeroTyp)), sizeof(wPlayer.HeroTyp)); nfin.read(reinterpret_cast< char*>(&(wPlayer.health)), sizeof(wPlayer.health)); //liest alles einzeln ein nfin.read(reinterpret_cast< char*>(&(wPlayer.mana)), sizeof(wPlayer.mana)); nfin.read(reinterpret_cast< char*>(&(wPlayer.maxdmg)), sizeof(wPlayer.maxdmg)); nfin.read(reinterpret_cast< char*>(&(wPlayer.mindmg)), sizeof(wPlayer.mindmg)); nfin.read(reinterpret_cast< char*>(&(wPlayer.defence)), sizeof(wPlayer.defence)); nfin.read(reinterpret_cast< char*>(&(wPlayer.level)), sizeof(wPlayer.level)); nfin.read(reinterpret_cast< char*>(&(wPlayer.xp)), sizeof(wPlayer.xp)); nfin.read(reinterpret_cast< char*>(&(wPlayer.geld)), sizeof(wPlayer.geld)); nfin.close(); //schließt den STream cout << "Account as read from binary file " <<dateiname <<endl; system("pause"); cout << wPlayer.name << endl; system("pause"); cout << wPlayer.HeroTyp << endl; system("pause"); cout << wPlayer.health << endl; system("pause"); cout << wPlayer.mana << endl; system("pause"); cout << wPlayer.maxdmg << endl; system("pause"); cout << wPlayer.mindmg << endl; system("pause"); cout << wPlayer.defence << endl; system("pause"); cout << wPlayer.xp << endl; system("pause"); cout << wPlayer.geld << endl; system("pause");und noch eine Frage warum muss ich den HeroTyp denn nicht auch so wie name umschreiben und er wird trotzdem richtig ausgegeben also bzw eingelesen ...
-
Du musst noch die Größe des Strings mitspeichern. Hier mal ein Minimalbeispiel:
#include <iostream> #include <fstream> #include <vector> void SaveString(std::ofstream& fout, const std::string& str) { int size = str.size(); fout.write(reinterpret_cast<const char*>(&size), sizeof(size));S fout.write(str.c_str(), size); } std::string LoadString(std::ifstream& fin) { int size; fin.read(reinterpret_cast<char*>(&size), sizeof(size)); std::vector<char> buf(size); fin.read(&buf[0], size); std::string temp(buf.begin(), buf.end()); // oder mit .assign(...) return temp; } int main() { std::ofstream fout("test.txt"); SaveString(fout, "Hallo Welt!"); SaveString(fout, "Test!"); fout.close(); std::ifstream fin("test.txt"); std::cout << LoadString(fin) << std::endl; std::cout << LoadString(fin) << std::endl; }
-
Öhm warum denn ? die Beiden Strings werden doch richtig einglesen nur die FLoat und integer Variablen der Klasse nicht !
..meinst du dann so ?
int size = wPlayer.size();
nfout.write(reinterpret_cast<const char*>(&size), sizeof(size));Sne oder das kann net sein man muss ja irgendwo die namen der strings reinbringen aber das mit den Strings klappt ja nur wie gesagt die Interger und FLoat Variablen der Klasse sPlayer machen Probleme , sieht man ja auch auf dem Bild ..der Name und der Typ wird richtig ausgegeebn aber die Zahlen nicht die dahinter FOlgen und dann noch eine andere Frage : Ich hab doch Binary als Typ angegeben aber man kann den Namen und den Typ einfach so in der txt lesen .