Überprüfung von objektorientiertem Code
-
drakon schrieb:
Unregistrierter schrieb:
Ups, jetzt fällt es mir erst auf. Es muss natürlich
else if( !witzig)heißen, für Farbe habe ich ja eine eigene Methode gebaut.
Danke für die guten Tipps, werde ich mir merken

Das dachte ich mir, dass da was falsches passiert.

Wobei auch diese überprüfung unsinnig wäre. Da kannst du doch einfach ein else machen.
Was aber auch noch nicht gut ist, wie asc bereits gesagt hat, wenn du jetzt eine Bibliothek schreibst (allgmein, nicht unbeding eine für Bücher), dann darf so etwas da gar nicht rein. Die Ausgabe hat ja nichts damit zu tun, ob es jetzt witzig ist, oder nicht. Du kannst natürlich den << - Operator überladen und dann eine Funktion schreiben, die dir alles auf einen std::ostream ausgibt, dann kannst du das nämlich wirklich einfach in eine Datei oder auf die Konsole ausgeben.Zum Beispiel so:
ostream& Buch::operator << (std::ostream& os, Buch const& buch) { if(buch.witzig) os << "witzig"; ... }Schau dir dazu einfach Operatorenüberladung an und wegen dem std::ostream musst du dich hald ein wenig mit der Standardbibliothek anfreunden.

Das verstehe ich nicht ganz. Wenn ich einen Comic erstelle, dann kann ich ja festlegen, ob er witzig ist (1 = Witzig).
Ist doch egal, ob ich dazu eine Funktion schreibe,
die den Bool in eine Ausgabe umwandelt, oder ob ich dafür den
ostream Operator überlade
Und warum lege ich mich damit auf die Console fest?
Die anderen Funktionen benutzen auch cout
else if( !witzig)Stimmt, da hätte ein else gereicht, danke für den Tipp

-
Unregistrierter schrieb:
Das verstehe ich nicht ganz. Wenn ich einen Comic erstelle, dann kann ich ja festlegen, ob er witzig ist (1 = Witzig).
Ist doch egal, ob ich dazu eine Funktion schreibe,
die den Bool in eine Ausgabe umwandelt, oder ob ich dafür den
ostream Operator überlade
Und warum lege ich mich damit auf die Console fest?
Die anderen Funktionen benutzen auch cout
Also du kannst dann so etwas schreiben:
Buch b; std::cout << "Das von ihnen gewaehlte Buch hat folgende Beschreibung: " << b; std::ofstream out ("buch.txt"); out << b;Du solltest dann die Informatinonen in der Funktion so formatieren, wie du es haben willst. (Natürlich nicht nur ob es witzig ist, sonder auch noch Name, Titel usw.)
Und das tolle ist,dass du das gleiche auch mit Files (oder anderen ostreams) machen kannst, ohne dir zu überlegen, wie du das jetzt (jedesmal) genau formatieren willst.
-
if( witzig ) cout << "witzig"; else if( !witzig ) cout << "nicht witzig";Aber um das kommt man bei deiner Methode ja auch nicht drum herum?
Ich erkläre nochmal genau was ich damit bezwecke.
Also mit dieser Methode gebe ich ja den Comic aus...void Comic::printcomic() { cout << "Titel: " << get_titel() << endl; cout << "Autor: " << get_autor() << endl; cout << "Seiten: " << get_seiten() << endl; cout << "Preis: " << get_preis() << endl; cout << "Farbe: "; this->testfarbe(farbe); cout << endl; cout << "Witzig: "; this->testwitzig(witzig); cout << endl << endl; }Damit will ich alle Eigenschaften ausgeben, also auch ob es Farben hat und ob es witzig ist. Aber ich kann ja nicht einfach schreiben
cout << farbebzw
cout << witzigdenn da farbe und witzig bools sind, würde das 0 oder 1 ausgeben. Darum habe ich diese Methode geschrieben, die dann witzig ausgibt, wenn witzig "eingeschaltet" ist. Wenn ich << überlade, dann würde das doch auch 0 oder 1 ausgeben, wenn man diese Methode weglässt. Sorry, ich stehe irgendwie auf der Leitung
-
Klar geht das, aber es tut nicht das, was manche erwarten würden.

Das hier wohl schon eher:
class buch { public: buch(bool w, int f, std::string n, int s, float p): witzig(w), farbe (f), name(n), seiten(s), preis(p){} //Beachte hier, dass du du die values bekommst. get sollte nichts ausgen, sondern nur //etwas ZURÜCKGEBEN. Also den erwarteten Wert. std::string get_titel () const {return name;} float get_preis () const {return preis;} //.. private: bool witzig; int farbe; std::string name; int seiten; float preis; //.. friend std::ostream& operator << (std::ostream& os, buch const& b); }; std::ostream& operator << (std::ostream& os, buch const& b) { b.witzig?os << "witzig\n":os << "nicht witzig\n" ; os << "Farbe: " << b.farbe << "\n"; os << "Name: " << b.name << "\n"; os << "Seiten: " << b.seiten << "\n"; os << "Preis: " << b.preis << "\n"; //.. return os; }buch c (true, 5, "hmm",10000,0.99f); std::cout << "Ihr gewaehltes Buch: \n" << c;btw:
value?anweisung1:anweisung2;
Nennt sich ternärer Operator. Wenn value wahr ist, mache anweisung1, sonst anweisung2.
-
jo stimmt, den << Operator zu überladen, wäre hier schon sinnvoll.
Aber da ich die Bücher sowieso nur auf der Console ausgeben will, rentiert es sich nicht, den Code zu ändern.
-
drakon schrieb:
btw:
Zitat:value?anweisung1:anweisung2;Nennt sich ternärer Operator. Wenn value wahr ist, mache anweisung1, sonst anweisung2.
und ist immer wieder herrlich unübersichtlich

b.witzig?os << "witzig\n":os << "nicht witzig\n" ;vs.
if (b.witzig) os << "witzig\n"; else os << "nicht witzig\n";oder:
if (!b.witzig) os << "nicht "; os << "witzig\n";aber ich würd wo das normale if bevorzugen ^^
bb
edit:
ach so - warum int farbe?
willst du die anzahl verwendeten farben speichern?
so, wie ich die klasse ma verstanden (überflogen) hatte, sollte das heißen, ob sie schwarz/weiß sind oder in farbe... aber das is ja eher nebensächlich
-
drakon schrieb:
value?anweisung1:anweisung2;
Nennt sich ternärer Operator. Wenn value wahr ist, mache anweisung1, sonst anweisung2.
Nö, Anweisungen dürfen da nicht stehen, nur Ausdrücke.
-
Bashar schrieb:
drakon schrieb:
value?anweisung1:anweisung2;
Nennt sich ternärer Operator. Wenn value wahr ist, mache anweisung1, sonst anweisung2.
Nö, Anweisungen dürfen da nicht stehen, nur Ausdrücke.
das halte ich für falsch...
bool tu_ichs_oder_nicht (true); tu_ichs_oder_nicht ? object->function ("ausdruck"):object->other_function ("ausdruck");
-
was willst du uns sagen? dass da nur ausdrücke (expressions) stehen dürfen? dann ergibt aber nichts mehr wirklich sinn
-
unskilled schrieb:
ach so - warum int farbe?
willst du die anzahl verwendeten farben speichern?
so, wie ich die klasse ma verstanden (überflogen) hatte, sollte das heißen, ob sie schwarz/weiß sind oder in farbe... aber das is ja eher nebensächlichEs soll anzeigen, ob es schwarz oder weiß ist. In meinem Code ist das auch ein bool. Das Problem war, dass ich die abgeleitete Klasse noch erweitern wollte, mir sind aber nur die Eigenschaften Farbe und witzig eingefallen.

-
Unregistrierter schrieb:
jo stimmt, den << Operator zu überladen, wäre hier schon sinnvoll.
Aber da ich die Bücher sowieso nur auf der Console ausgeben will, rentiert es sich nicht, den Code zu ändern.Gerade diese Denkweise wird dir schnell zum Kreuz. Vom OO Design Standpunkt (und um den ging es dir ja u.a. auch im ersten Posting) sollten die Klassen die Daten halten nichts mit den Klassen zu tun haben, die diese Daten ausgeben. Das sorgt dafür, dass auch 3 Monate später, wenn man seine Bilbiothek zu Übungszwecken mal in eine GUI Anwendung packen will, nicht den ganzen Code umschreiben muss, der nur für die Daten zuständig ist, sondern diesen einfach wiederverwenden kann - ein Kernaspekt von gutem OO Design.
-
Aber wenn ich den ostream Operator überlade, kann ich das doch
auch nicht in eine GUI Anwendung packen, da es ja iostream ist.
-
Unregistrierter schrieb:
Aber wenn ich den ostream Operator überlade, kann ich das doch
auch nicht in eine GUI Anwendung packen, da es ja iostream ist.iostream gehört zur Standardbibliothek und ist somit eigentlich überall verfügbar.
-
Aber iostream arbeitet doch mit cout, und das ist doch nur Console?
Hast du zufällig nen Link mit Code, bei dem das mit der WinApi gemacht wird?
-
Unregistrierter schrieb:
Aber iostream arbeitet doch mit cout, und das ist doch nur Console?
Hast du zufällig nen Link mit Code, bei dem das mit der WinApi gemacht wird?http://www.cplusplus.com/reference/iostream/cout.html
So ist das von Seiten C++ definiert.
Der Standard schreibt lediglich vor, dass cout auf den Standardoutput schreibt.
Mit der WinAPI wird das wahrscheinlich irgendwann damit gemacht:http://msdn.microsoft.com/en-us/library/ms687401(VS.85).aspx
-
Unregistrierter schrieb:
Aber iostream arbeitet doch mit cout, und das ist doch nur Console?
Hast du zufällig nen Link mit Code, bei dem das mit der WinApi gemacht wird?Du hast die stream-Abstraktion noch nicht verstanden. Ein Stream ist erstmal etwas abstraktes, ein Konzept. Er sagt nicht, das er auf der Konsole landet. Er landet irgendwo, und das irgendwo kannst du bestimmen. Du schreibst etwas in einen Stream, weißt aber nicht, wo es landet. Der Benutzer deiner Klasse, entscheidet dann aber konkret, wo der Stream landet: auf Konsole, Festplatte, Drucker usw.
Gerade das abstrakte Denken ist die Herausforderung in der Objektorientierung. Das es aber nicht von Anfang an geht, ist jedoch verständlich. Mit der Zeit wirst du es aber selber heraus finden, wenn du mehrmals auf die Nase fällst. Meistens muß man Fehler machen, um später zu erkennen, das es anders doch besser geht.

-
achso, jetzt verstehe ich das. Ich dachte iostream ist nur Console.
Dann ändere ich das mal. Danke für den Tipp
-
Hallo
Wenn du eine interessante Übungsaufgabe suchst: Versuch es doch mal mit einer Klasse die das BackUp von Dateien übernimmt. Da kann man viel mit machen, auch zwei oder mehr Klassen entwickeln. Viele verschiedene Möglichkeiten der Projektgestaltung. Und man lernt super wie es ist auch bei komplexeren (und sinnvollen ^^) Projekten sauberen OOP C++ Code zu basteln.mal als Anstoß, was man machen kann:
- Liste von Backups, Ausführung von Backups (Manuelle / Automatische (Datums / Zeitangaben).
- Neue Backupjobs, Backupjobs löschen
- Logfile der Backups - Übersicht / Statistik über gemachte Backups, Dateimenge (Speicherplatz)
- Zielverzeichnis ändern, Backupjobs Namen geben, umbenennen. Komplettes Backup woanders hin kopieren.Das hab ich sozusagen für mich selber als Einstieg in die Klassenprogrammierung gemacht und das hat super funktioniert.

EDIT: Vorteil des Projekts: Du kannst es vielleicht sogar gebrauchen^^
-
und noch was
du hast anscheinend die zugriffsmethoden nur geschrieben damit comic darauf zugreifen kann
warum nicht gleich als friend deklarieren
-
Könnt ihr diesen Code bitte auch durchsehen?
Mein 1. Versuch ein kleines TicTacToe zu programmieren
Leider habe ich mich hier aufgrund von cout wieder an die Console gebunden,
da ich das Projekt vor euren guten Ratschlägen gestartet habe.
Funktioniert bis jetzt leider nur mit 2 Spielern.Kennt einer einen Lösungsweg, wie ich hier eine KI adden könnte?
Ich hab mir schon überlegt, alles mit if abfragen zu erledigen.
Also wenn Feld 0 und 1 besetzt sind, dann 2 besetzten. Das würde aber
einen sehr langen, unübersichtlichen Code ergeben und eine KI, die immer das gleiche macht.
Hier mal der Code...
Wie immer freue ich mich über Tipps/Verbesserungsvorschläge
#include <iostream> #include <string> #include <windows.h> using std::cout; using std::endl; using std::cin; using std::string; class TTT { string feld[9]; public: void print_feld(); void intro(); void auswahl( int auswahl ); void auswahl2( int auswahl ); bool test_ttt(); }; int main() { TTT game; game.intro(); game.print_feld(); cout << "Willkommen bei TicTacToe." << endl; int pos; for (;;) { cout << "Spieler 1, bitte Position angeben, an der Sie setzten wollen!" << endl << endl << endl; cin >> pos; game.auswahl( pos ); game.print_feld(); if( game.test_ttt() ) { break; } cout << "Spieler 2, bitte Position angeben, an der Sie setzten wollen!" << endl << endl << endl; cin >> pos; game.auswahl2( pos ); game.print_feld(); game.test_ttt(); } system("PAUSE"); return 0; } void TTT::print_feld() { cout << " " << "| |" << endl; // 7 Leer cout << " " << "| |" << endl; cout << " " << "| |" << endl; cout << " " << feld[0] << " " << "| " << feld[1] << " | " << feld[2] << endl; cout << " " << "| |" << endl; cout << " " << "| |" << endl; cout << " " << "| |" << endl; cout << "------------------------" << endl; // 24 cout << " " << "| |" << endl; cout << " " << "| |" << endl; cout << " " << feld[3] << " " << "| " << feld[4] << " | " << feld[5] << endl; cout << " " << "| |" << endl; cout << " " << "| |" << endl; cout << "------------------------" << endl; cout << " " << "| |" << endl; // 7 Leer cout << " " << "| |" << endl; cout << " " << "| |" << endl; cout << " " << feld[6] << " " << "| " << feld[7] << " | " << feld[8] << endl; cout << " " << "| |" << endl; cout << " " << "| |" << endl; cout << " " << "| |" << endl << endl; } void TTT::intro() { feld[0] = "1"; feld[1] = "2"; feld[2] = "3"; feld[3] = "4"; feld[4] = "5"; feld[5] = "6"; feld[6] = "7"; feld[7] = "8"; feld[8] = "9"; } void TTT::auswahl( int auswahl ) { for( int i = 1; i != 10; ++i ) { if( auswahl == i ) feld[i-1] = "X"; } } void TTT::auswahl2( int auswahl ) { for( int i = 1; i != 10; ++i ) { if( auswahl == i ) feld[i-1] = "!"; } } bool TTT::test_ttt() { if( feld[0] == feld[1] && feld[1] == feld[2] && feld[0] == "X" ) { cout << "GLUECKWUNSCH SPIELER 1" << endl; return 1; } if( feld[0] == feld[1] && feld[1] == feld[2] && feld[0] == "!" ) { cout << "GLUECKWUNSCH SPIELER 2" << endl; return 1; } if( feld[3] == feld[4] && feld[4] == feld[5] && feld[5] == "X" ) { cout << "GLUECKWUNSCH SPIELER 1" << endl; return 1; } if( feld[3] == feld[4] && feld[4] == feld[5] && feld[5] == "!" ) { cout << "GLUECKWUNSCH SPIELER 2" << endl; return 1; } if( feld[6] == feld[7] && feld[7] == feld[8] && feld[6] == "X" ) { cout << "GLUECKWUNSCH SPIELER 1" << endl; return 1; } if( feld[6] == feld[7] && feld[7] == feld[8] && feld[6] == "!" ) { cout << "GLUECKWUNSCH SPIELER 2" << endl; return 1; } if( feld[0] == feld[3] && feld[3] == feld[6] && feld[0] == "X" ) { cout << "GLUECKWUNSCH SPIELER 1" << endl; return 1; } if( feld[0] == feld[3] && feld[3] == feld[6] && feld[0] == "!" ) { cout << "GLUECKWUNSCH SPIELER 2" << endl; return 1; } if( feld[1] == feld[4] && feld[4] == feld[7] && feld[1] == "X" ) { cout << "GLUECKWUNSCH SPIELER 1" << endl; return 1; } if( feld[1] == feld[4] && feld[4] == feld[7] && feld[1] == "!" ) { cout << "GLUECKWUNSCH SPIELER 2" << endl; return 1; } if( feld[2] == feld[5] && feld[5] == feld[8] && feld[2] == "X" ) { cout << "GLUECKWUNSCH SPIELER 1" << endl; return 1; } if( feld[2] == feld[5] && feld[5] == feld[8] && feld[2] == "!" ) { cout << "GLUECKWUNSCH SPIELER 2" << endl; return 1; } if( feld[0] == feld[4] && feld[4] == feld[8] && feld[0] == "X" ) { cout << "GLUECKWUNSCH SPIELER 1" << endl; return 1; } if( feld[0] == feld[4] && feld[4] == feld[8] && feld[0] == "!" ) { cout << "GLUECKWUNSCH SPIELER 2" << endl; return 1; } if( feld[2] == feld[4] && feld[4] == feld[6] && feld[2] == "X" ) { cout << "GLUECKWUNSCH SPIELER 1" << endl; return 1; } if( feld[2] == feld[4] && feld[4] == feld[6] && feld[2] == "!" ) { cout << "GLUECKWUNSCH SPIELER 2" << endl; return 1; } // alle belegt = Unentschieden if( feld[0] != "1" && feld[1] != "2" && feld[2] != "3" && feld[3] != "4" && feld[4] != "5" && feld[5] != "6" && feld[6] != "7" && feld[7] != "8" && feld[8] != "9" ) { cout << "UNENTSCHIEDEN!" << endl; return 1; } }EDIT: Noch ne Frage zu dem Library Code:
Welches using muss man machen, um auf std:: vor ostream zu verzichten?
Ich habe gelesen das man aufusing namespace std;verzichten sollte,
und darum würde ich das gerne mitusing std::funktion;machen.