Programm zum schreiben und lesen von .txt Dateien
-
Warum nimmt der Konstruktor eigentlich einen char-Zeiger entgegen? Du programmierst doch auch schon ein Weilchen, nimm doch wenigstens const char*, oder besser noch const std::string&.
Und hier:
string clause=""; do { getline(cin,clause); file << clause; }while(clause != "exit");Solltest du vielleicht vor dem Schreiben auf "exit" prüfen, sonst endet jede deiner Textdateien mit "exit"

Wieso das Programm nicht wie gewünscht funktioniert, weiß ich nicht, Kennys Hypothese hört sich aber glaubhaft an. Noch ne Frage: In der main-Funktion erstellst du mit new eine Instanz, warum keine auf dem Stack?
-
Hallo,
Mach mal aus m_file_name einen string sonst schleifts du irgendwann mal ungültige Zeiger mit. Teste den Rückgabewert von open_file() um festzustellen ob die Datei überhaupt geöffnet wurde (auch bitte in handle_file mit is_open testen).
-
Mh, total merkwürdig, ich hab jetzt erst alles in "stings" umgeschrieben, so wie ihrs gesagt habt....dann gings. Dann hab ich alles rückgängig gemacht (mit Strg + "Z")....und es war wieder mit char, wie ganz am anfang....und plötzlich gings auch....is aber noch genau das gleiche wie vorhin..voll merkwürdig, ich weiß nicht was ich verändert haben soll...!?!
Na ja zumindestens mach ich das dann mit string, das blöde ist halt, das die Methode "open()" char entgegenimmt, aber da mach ich dann halt einfach "string.c_str()" jetzt.
Meint ihr da ist auch n Geschwindigkeitsunterschied wenn ich das mit strings mache, oder einfach nur sicherer und verständlicher?@Badestrand
Äh du hast gesagt ".... oder besser noch const std::string&." Warum hast du das mit Referenz hingeschrieben, die ist doch nicht neutig oder? Vor 3-4 Tagen hab ich erst n Thread aufgemacht und drüber geredet wann genau man Referenzen anwendet, weil ich das immer noch nicht so ganz gecheckt hatte ...und so meine Faustregel war dann am ende: "Nur da wo man auch Variablen außerhalb verändern möchte"....das erschüttert mein Weltbild jetzt wieder n bisschen
Kannst du mir sagen warum du da eine Referenz gewählt hast?MfG
StrombergEDIT:
So ist die Methode "handle_file" besser:void write::handle_file() { string clause=""; while(getline(cin,clause)) { if (clause == "exit") break; file << clause; } }EDIT2:
Bademeister schrieb:
In der main-Funktion erstellst du mit new eine Instanz, warum keine auf dem Stack?
Was meinst du mit auf dem Stack? Ich hab gedacht man muss das mit dem "new..." immer so machen, sonst funktionieren die virtuellen Methoden nicht mehr?! Oder wie hast du das gemeint, ich glaub ich hab mal wieder eine große Wissenslücke? Aber in meinem Buch wurde es bis jetzt immer mit "Klasse *object=new Klasse2(...)" gemacht, nie anderst..
Irgendwie steh ich glaub auf der Leitung.
MfG
Stromberg
-
Stromberg schrieb:
@Badestrand
Äh du hast gesagt ".... oder besser noch const std::string&." Warum hast du das mit Referenz hingeschrieben, die ist doch nicht neutig oder? Vor 3-4 Tagen hab ich erst n Thread aufgemacht und drüber geredet wann genau man Referenzen anwendet, weil ich das immer noch nicht so ganz gecheckt hatte ...und so meine Faustregel war dann am ende: "Nur da wo man auch Variablen außerhalb verändern möchte"....das erschüttert mein Weltbild jetzt wieder n bisschen
Kannst du mir sagen warum du da eine Referenz gewählt hast?Klar kann ich das sagen

Es gibt ja ein paar Varianten, wie man eine Zeichenkette übergeben könnte:
char*ist das denkbar schlechteste (für diese Situation), weil du damit ja sagst "ja, vielleicht verändere ich die Zeichenkette, mal sehen". Wenn jemand, der deinen Konstruktor aufrufen möchte, nur einen String alsconst char*vorliegen hat, kann er deinen Konstruktor schlicht und einfach nicht aufrufen, was ja wohl echt doof wäre
(bla bla, es gibt const_cast, ist aber eine der widerwärtigsten Sachen überhaupt)
Bleiben noch Übergaben viastring,string&,const stringundconst string&. Die einfach string-Referenz wollen wir nicht, schließlich wollen wir den String nicht verändern. Mitstringundconst stringerzeugen wir unnötigerweise eine Kopie, wollen wir also auch nicht.
Bleibt also nurconst string&undconst char*.const string&erzeugt imho zwar auch eine Kopie, falls du z.B. einen rohen Text übergibst (Zeug in Anführungsstrichen), dafür kannst du die einfachen String-Funktionen benutzen.const char*kannst du auch nehmen, dann darfst du in deiner Klasse aber nicht den Zeiger speichern, sondern eben nur eine Kopie des Strings.
Wegen des Stils würde ich definitivconst string&bevorzugen, da du damit auch zeigst, dass du eine Zeichenkette willst, char-Zeiger könnten auch Binärdaten sein. Gut, der Parameter heißt "file_name" oder so, da erkennt man's, meiner Meinung nach sollte man aber durchgehend 'std::string's für Zeichenketten benutzen (macht auch vieles sehr viel angenehmer und sicherer).Im Übrigen würde ich dir stark empfehlen, viel mit 'const' zu arbeiten. 'const' macht deine Programme nicht nur sicherer, der Compiler kann auch besser optimieren. Konstante Referenzen findet man übrigens recht häufig als readonly-Parameter.
Ach, und ich denke Zeiger sind eine der häufigsten Fehlerursachen in C++, bzw wenn man bei Zeigern mal irgendwas übersieht. Falls du Boost drauf hast, solltest/könntest du dir mal shared_ptr angucken. Wenn du diese und eben konstante Referenzen viel nutzt (überall wo möglich/nötig/sinnvoll), wirst du irgendwann nur noch sehr selten mit rohen Zeigern arbeiten (das ist dann was Gutes :)).
Zweiter Nachtrag: Während du Funktionen spezifizierst, bzw sie schreiben willst, solltest du dir immer überlegen, welche Parameter sie braucht, welche davon nur gelesen werden (dann konstante Referenz für Objekte oder call-by-value für int, char, float usw) und welche Daten empfangen (dann am Besten nur Referenz).
Ups, nochwas: Bekommt eine deiner Funktionen einen Zeiger übergeben nimmst du damit in Kauf, evtl auch einen Null-Zeiger zu bekommen. Theoretisch müsste man das immer überprüfen, schließlich ist das ein 'gültiger' Zeiger-Wert/-Zustand. Benutzt du Referenzen als Parameter, sagst du damit aus, dass nur valide Objekte übergeben werden dürfen. Wird also eine Referenz übergeben, die intern auf Null zeigt, liegt der Fehler ganz klar bei der aufrufenden Funktion, da du ja ein gültiges Objekt "erwartest".
Nimmt man Zeiger entgegen, kannst du in die Doku oder Kommentare schreiben, dass du keinen Null-Zeiger willst, die "Forderung" nach validen Objekten ist bei Referenzen aber weit stärker, vor allem da manche Funktionen bei Zeigern auch gerne mal Null-Pointer akzeptieren.
Das Ganze erinnert mich gerade an Design By Contract, naja ich denke du weißt was ich dir sagen wollte :xmas2:
-
Verdammt, genau da wo du geschrieben hast, hab ich nochmal editiert:
Stromberg schrieb:
Bademeister schrieb:
In der main-Funktion erstellst du mit new eine Instanz, warum keine auf dem Stack?
Was meinst du mit auf dem Stack? Ich hab gedacht man muss das mit dem "new..." immer so machen, sonst funktionieren die virtuellen Methoden nicht mehr?! Oder wie hast du das gemeint, ich glaub ich hab mal wieder eine große Wissenslücke? Aber in meinem Buch wurde es bis jetzt immer mit "Klasse *object=new Klasse2(...)" gemacht, nie anderst..
Irgendwie steh ich glaub auf der Leitung.MfG
Stromberg
-
Stromberg schrieb:
Bademeister schrieb:
In der main-Funktion erstellst du mit new eine Instanz, warum keine auf dem Stack?
Was meinst du mit auf dem Stack? Ich hab gedacht man muss das mit dem "new..." immer so machen, sonst funktionieren die virtuellen Methoden nicht mehr?! Oder wie hast du das gemeint, ich glaub ich hab mal wieder eine große Wissenslücke? Aber in meinem Buch wurde es bis jetzt immer mit "Klasse *object=new Klasse2(...)" gemacht, nie anderst..
Irgendwie steh ich glaub auf der Leitung.Bade**strand*** bitte
Du hast da was durcheinandergeworfen, bei virtuellen Methoden wird immer die richtige aufgerufen, bei nicht-virtuellen nur immer die Methode vom aktuellen Typ. Ob das Objekt auf dem Stack oder Heap liegt, spielt dabei (zum Glück) keine Rolle 
*In Java unterscheidet man zwischen 'statischen' und 'dynamischen' Typen. Guckstu hier:
class Tier; class Hund : public Tier; class Katze : public Tier; ... void Bla( const Tier* viech ) { // Falls die Methode "NervMich" als virtuell deklariert ist, wird die richtige aufgerufen, falls sie nicht virtuell // ist, wird die von Tier aufgerufen, da das der "aktuelle Typ" ist. viech->NervMich(); } void AkteXY_Ungelöst() { Hund grosses_viech; Katze kleines_viech; Bla( &grosses_viech ); Bla( &kleines_viech ); }
-
Und wie mach ich das dann auf n Stack, kannst du mir mal den Codeschnippsel von der deklaration hinhaun, versteh das grad irgendwie nicht.
MfG
Stromberg
-
int main() { write object1("D:/Rechnung.txt"); object1.open_file(); object1.handle_file(); return 0; }Aber ok, sorry, hatte übersehen, dass du (wahrscheinlich absichtlich) die Typinformation rausgeschmissen hast

-
Mh, sry aber ich bin immer no bissel verwirrt.
Weil so wie du das jetzt machst, stimmt so gehts ja auch, aber jetzt kann ich mir eigentlich meine virtuellen Methoden in "text_editor" stecken, mit denen kann ich ja nix mehr anfangen oder?!
Meine Idee zu "Objekt nicht auf dem Heap" wäre noch folgende gewesen:text_editor object("D:/Werner.txt"); ....Aber das geht ja nicht, weil die Klasse "text_editor" is ja abstrakt. Ich könnte natürlich das "abstrakt" wegmachen, dann würde ses gehen, dann müsste ich aber jede Methode extra nochmal für "text_editor" initialisieren.
Also bis jetzt geht das mit den "virtuellen Methoden", und dem "abstrakt" doch nur bei der Form: "text_editor object=new write(...)"....
Oder was meinst du dazu? Ich hab irgendwie immer gedacht das wäre die standard Form dazu....ka...gut anderst gehts mit den virtuellen Methoden auch, wie schon gesagt, aber "text_editor" is ja abstrakt.
Mh, ich glaub die ganze verkorkste denkweise von mir liegt nur an meinem Buch, "Jetzt lerne ich C++"...ich glaub ohne dieses sch** Buch hätt ich viel früher, viel besser, viel logischer programmiert....
BITTE KAUFT SICH KEIN C++ ANFÄNGER MEHR DIESES BUCH. Ohne witz, ich glaub ich wär mit nem gescheiten Buch, schon n halbes Jahr weiter an Wissen....So jetzt noch zu den Referenzen:
Wie dus erklärt hast, kann ich dann einfach für mich die Faustregel aufstellen:Bei Parameter, die innerhalb der Funktion\Methode verwendet werden um sie zu lesen, nimmt man bei Objekten (oder z.B. string..., weil string ist ja auch nix anderes als ein Objekt) const Referenzen, und bei normalen Datentypen (int, long, double, char, float, short) call-by-value.
Parameter, mit denen man außerhalb der Funktion Variablen etc. verändert, nimmt man immer Referenzen.Passt dass so? Dann würd ichs mir gleich ganz dick und fett auf nen Zettel schreiben!!!

MfG
StrombergPS: Stimmt, du heißt natürlich Badestrand sry. Kannst mich dann jetzt Strombose nenne, wer Stromberg gugt, musst aber n Stromberg guger sein, um zu verstehen was es mit Strombose auf sich hat^^.
-
es ist eben blöd, wenn gefordert wird, etwas zu verwenden (hier: polymorphie), wenn man es eigentlich auch ohne lösen könnte.
frage: ist read ein text_editor?
-
Hi Badestrand,
du bist ja Kriterien durchgegangen, wann man sich für welche Art
Übergabetyp entscheiden sollte.
Vielleicht steh ich gerade auf dem Schlauch.
Wann brauch ich sowas "const string"?
Wenn es const ist, brauch ich doch keine Kopie erstellen und kann ne Referenz
verwenden. Da das Objekt const ist, kann ich es eh nicht verändern, folglich
macht die Kopie keinen (?) Sinn.
Klar macht es Sinn, wenn man sich in irgendwelchen const-Methoden (jetzt nicht auf
string bezogen) das Objekt "kaputtschreibt", allerdings spricht das ja gegen das
const-Konzept.
Kannst du mir evtl. nen Beispiel nennen, wo man sowas braucht. Evtl. in
irgendwelchen Multithreading-Kontexten, wo ich mir das Objekt beim Starten
eines neuen Threads und verlassen den Scopes unterm A**** wegziehe?
Oder in Kontexten, wo der Copy-Konstruktor anders als üblich implementiert ist?
Ich denke da gerade an auto_ptr, so kann man sicherstellen, dass ein Objekt nach einem Aufruf nicht mehr verfügbar ist. Aber macht das Sinn?
Bevor ich jetzt weiter vor mich hin philosophiere, kann mir sicher jemand
ein Beispiel nennen ^^Gruß,
CSpille
-
Mh ja, weiß nich, net so richtig oder? Abuer gut write gehört zum Texteditor dazu, weil der Texteditor kann Dateien beschreiben. Read gehört auch zum Texteditor dazu, weil der Texteditor lesen kann. Ja kp, ich wollt halt mal des ganze Zeugsl mit reinpacken, ums auch mal anzuwenden.
Aber am besten mach ich jetzt ein Klasse "read" eine Klasse "write" und eine Klasse "text_editor" (keine ist verwnadt mit irgend einer anderen. Und in "text_editor" beinfet sich dann ein read Objekt und ein write Objekt mit denen ich dann die anwenderfreundlichern Methoden in "text_editor" kreiere...
Hört sich schon besser an?
MfG
Stromberg
-
CSpille schrieb:
Hi Badestrand,
du bist ja Kriterien durchgegangen, wann man sich für welche Art
Übergabetyp entscheiden sollte.
Vielleicht steh ich gerade auf dem Schlauch.
Wann brauch ich sowas "const string"?
Wenn es const ist, brauch ich doch keine Kopie erstellen und kann ne Referenz
verwenden. Da das Objekt const ist, kann ich es eh nicht verändern, folglich
macht die Kopie keinen (?) Sinn.
Klar macht es Sinn, wenn man sich in irgendwelchen const-Methoden (jetzt nicht auf
string bezogen) das Objekt "kaputtschreibt", allerdings spricht das ja gegen das
const-Konzept.
Kannst du mir evtl. nen Beispiel nennen, wo man sowas braucht. Evtl. in
irgendwelchen Multithreading-Kontexten, wo ich mir das Objekt beim Starten
eines neuen Threads und verlassen den Scopes unterm A**** wegziehe?
Oder in Kontexten, wo der Copy-Konstruktor anders als üblich implementiert ist?
Ich denke da gerade an auto_ptr, so kann man sicherstellen, dass ein Objekt nach einem Aufruf nicht mehr verfügbar ist. Aber macht das Sinn?
Bevor ich jetzt weiter vor mich hin philosophiere, kann mir sicher jemand
ein Beispiel nennen ^^wenn sowieso eine kopie erstellt wird, ist es nicht nötig, sie const zu machen, ja. außer vielleicht, um dich selbst vor fehlern zu schützen (aber dann: warum eine kopie und nicht gleich eine konstante referenz?) einmal abgesehen von situationen, in denen der copy-ctor so unglaublich seltsame dinge macht (einen auto_ptr per konstanter kopie übergeben? das macht wohl nichts als ärger)
die einzige sinnvolle verwendung für const-value-übergaben, die mir gerade (zu später stunde) einfällt, ist bei (freien) überladenen operatoren als return-typ.Stromberg schrieb:
Mh ja, weiß nich, net so richtig oder? Abuer gut write gehört zum Texteditor dazu, weil der Texteditor kann Dateien beschreiben. Read gehört auch zum Texteditor dazu, weil der Texteditor lesen kann. Ja kp, ich wollt halt mal des ganze Zeugsl mit reinpacken, ums auch mal anzuwenden.
Aber am besten mach ich jetzt ein Klasse "read" eine Klasse "write" und eine Klasse "text_editor" (keine ist verwnadt mit irgend einer anderen. Und in "text_editor" beinfet sich dann ein read Objekt und ein write Objekt mit denen ich dann die anwenderfreundlichern Methoden in "text_editor" kreiere...
Hört sich schon besser an?
MfG
Strombergbesser als die vererbung, ja

-
@Badestrand
Wär die Regelung gut?:
Bei Parameter, die innerhalb der Funktion\Methode verwendet werden um sie zu lesen, nimmt man bei Objekten (oder z.B. string..., weil string ist ja auch nix anderes als ein Objekt) const Referenzen, und bei normalen Datentypen (int, long, double, char, float, short) call-by-value.
Parameter, mit denen man außerhalb der Funktion Variablen etc. verändert, nimmt man immer Referenzen.Noch was zur Vererbung, ich hab da den Grundgedanken glaub noch nicht verstanden (also ich weiß schon wie mans anwendet)....aber ist eine Vererbung nur gut, wenn ich sagen kann....Unterklasse ist ein "Basisklasse".
z.B.
class Dateiformat;Jpeg : public Dateiformat;
Bmp : public Dateiformat;Bmp16Byte : public Bmp;
Bmp32Byte : public Bmp;
JpegHighKopmression : public Jpeg;
JpegLowKopmression : public Jpeg;
....
......
Das wäre aber doch eine richtige Vererbung jetzt oder?Aber so was geht nicht - weil ich hab gedacht das könnte man auf dies Art und weise auch machen, oder vll. gibts da vll. auch verschiedenen Bennungen von den Vererbungen? Oder gibts nur diese eine Art (siehe oben) - oder?
class Auto;
Motor : public Auto;
Karosserie : public Auto;Baterie : public Motor;
Zylinder : public Motor;
....Raeder : public Karosserie;
Auspuff : public Karosserie;
.....So was wäre falsch oder?
Könnt ihr mir noch n paar gute Vererbungsbeispiele geben, damit ichs besser verstehe?
MfG
Stromberg
-
kurz gesagt: öffentliche (public) vererbung beschreibt eine ist-ein beziehung.
(genauer: man kann ein objekt der von B abgeleiteten klasse D so verwenden, als wäre es ein objekt vom typ
Jpeg ist ein Dateiformat, wenn du ein Objekt Jpeg genauso verwenden kannst, wie ein Objekt Dateiformat, dann stimmt die beziehung.
kannst du das? das wird auf den konkreten fall ankommen, auf die aufgabe, die du hast. wenn du sagst jpeg stellt eine art von datei dar, dann stimmt die beziehung z.b. nicht, dann ist jpeg vielleicht eine Datei, aber kein dateiformat.eine hochkomprimiertes jpeg-datei ist eine jpeg-datei. kannst du eine hochkomprimierte jpeg-datei genauso verwenden, wie eine jpeg datei? vielleicht. kommt wieder darauf an. ich tendiere zu nein, das "hochkomprimieren" könntest du dann vielleicht als template-policy implementieren - oder als decorator.
ja, einfach ist es bei diesen beispielen:
Motor : public Auto;
Karosserie : public Auto;ein Motor ist nie ein Auto. falsche beziehung - keine öffentliche vererbung
eine Karosserie ist kein Auto. falsche beziehung - keine öffentliche vererbung
hier wäre eine hat-ein beziehung angebracht, also womöglich komposition.die theorie dahinter findest du hier:
http://de.wikipedia.org/wiki/Vererbung_(Programmierung)
http://de.wikipedia.org/wiki/Liskovsches_Substitutionsprinzip
-
CSpille schrieb:
Hi Badestrand,
du bist ja Kriterien durchgegangen, wann man sich für welche Art
Übergabetyp entscheiden sollte.
Vielleicht steh ich gerade auf dem Schlauch.
Wann brauch ich sowas "const string"?Stimmt schon, "const string" macht meiner Meinung nach auch keinen Sinn, ich wollte nur der Vollständigkeit halber alle Varianten aufzählen

Stromberg schrieb:
Wär die Regelung gut?:
Bei Parameter, die innerhalb der Funktion\Methode verwendet werden um sie zu lesen, nimmt man bei Objekten (oder z.B. string..., weil string ist ja auch nix anderes als ein Objekt) const Referenzen, und bei normalen Datentypen (int, long, double, char, float, short) call-by-value.
Parameter, mit denen man außerhalb der Funktion Variablen etc. verändert, nimmt man immer Referenzen.Deinen letzten Satz verstehe ich nicht ganz, meinst du vielleicht 'innerhalb'?
Ich halte es generell so:void function( int read1, int& write1, const string& read2, string& write2 ) { //... }Bei angewandter Polymorphie kommt man auch um Zeiger drumherum:
class A { public: virtual void Do() const { cout << "A::Do()" << endl; } }; class B : public A { public: virtual void Do() const { cout << "B::Do()" << endl; } }; class C : public A { public: virtual void Do() const { cout << "C::Do()" << endl; } }; void Foo( const A& a ) { a.Do(); } int main() { A* a = new B(); Foo( *a ); return 0; } // Ausgabe "B::Do()"
-
Mit "Parameter, mit denen man außerhalb der Funktion Variablen etc. verändert, nimmt man immer Referenzen.", hab ich halt gemeint, das wenn ich eine Variable außerhalb des Funktionsscope verändern möchte.
void func(int &value); int main() { int a=5; cout << a << endl; //Ausgabe: 5 func(a); cout << a << endl; //Ausgabe: 10 return 0; } void func(int &value) { value=10; }Ist aber eigentlich ganz selbstverständlich.

Also dann schreib ich mir das mal ganz dick und fett auf nen Zettel, ich hoff das wir meinen Stil verbessern.
**
Bei Parameter, die innerhalb der Funktion\Methode verwendet werden um sie zu lesen, nimmt man bei Objekten (oder z.B. string..., weil string ist ja auch nix anderes als ein Objekt) const Referenzen, und bei normalen Datentypen (int, long, double, char, float, short) call-by-value.
Parameter, mit denen man außerhalb der Funktion Variablen etc. verändert, nimmt man immer Referenzen.
**MfG
Stromberg