Was ist für euch guter Programmcode?
-
Ursprünglich ging es uns ja eigentlich darum, inwieweit grosszügige Kommentierung zu einem guten Programmcode beiträgt.
Die MS-VC++.net 2003 IDE hat beispielsweise die nette Eigenart, Kommentare, die sie in der Nähe von Funktionsdeklarationen in einem Header entdeckt, als zusätzlichen Balloontip einzublenden, wenn man den Funktionsnamen irgendwo anders in einem Modul verwendet und sich nicht mehr ganz sicher ist, was eine Funktion genau machen soll oder kann, die man sich beispielsweise eine Woche vorher im Header ausgedacht hat.Bitte, ein Beispiel für eine gelungene Architektur eines etwas größeren Projektes, das, wie ich meine, auch sehr gut gelungen ist (trotz tief geschachtelter Schleifen) koennt ihr an diesem Header erkennen:
/* SO UND DAS IST DER HEADER MEINER MECNELS TACTICS VORVERSION extra fuer meine Freunde bei www.c-sar.de Das Hauptprogramm und die Bibliothek, die sich um die Realisierung der Methoden kuemmert, die hier nur deklariert werden, machen zusammen stolze 1600 Codezeilen aus und ich verzichte darum darauf, sie mitzuliefern Compiliert ist das nette Spielchen in MS-VC++.net 2003 und läuft in jedem Fall auf WinME, Win2000 und WinXP (da hab ich es jedenfalls selber getestet), wahrscheinlich auch Win98. Wie versprochen hier eine kurze Spielanleitung: Fuer diejenigen, die das Vorbildspiel Stratego schon kennen, sei kurz vorweg erwaehnt, dass die Wertigkeit der Spielsteine in dieser Version am Palettenfeld rechts zu erkennen ist, und zwar von links oben nach rechts unten ansteigend. Das Erdbeereis entspricht der Fahne, der Devil dem Spion, die Fliege dem Aufklaerer, die Spinne dem Mineur und die Zecke entspricht den Bomben bei Stratego. Zuerst muesst ihr Eure Spielfiguren (dargestellt durch Tierfotos) in der Aufstellungszone des Spielfeldes (untere 4 Reihen) in Position bringen. Einfach mit der Maus von der Palette nehmen und auf dem Spielfeld platzieren. Wenn ihr dann genug aufgestellt habt (40 Leutchen) (alternativ übernimmt das Aufstellen der Steine auch das Programm für Euch, wenn ihr auf Quickstart drückt) klickt ihr auf den unspektakulaeren OK-Button rechts unten. Der Computer ist gnaedig und lasst Euch den ersten Zug machen, ihr braucht eigentlich nur ein Start- und ein Zielfeld eingeben, damit der ausgefuehrt wird. Ihr muesst Eure Spielzuege immer mit einem Klick irgendwo auf dem Spielfeld abschliessen, damit der Computer seinen Zug ausfuehrt. Das geht mitunter ziemlich flott vor sich, also solltet Ihr gut aufpassen, um Eure Chancen zu erhoehen. Die Zecken und das Erdbeereis koennen nicht bewegt werden. Die Fliegen koennen fast beliebig weit ziehen, probiert es einfach aus. Alle anderen Spielsteine koennen immer nur um ein Feld bewegt werden. Abwechselnd mit dem Computer macht Ihr Eure Zuege, bis einer von Euch das Erdbeereis des Gegners erobert. Wie bereits erwaehnt haben die Spielfiguren unterschiedliche Kampfwerte, von denen es abhaengt, wer im Falle eines Gefechtes am Spielfeld bleibt. Prinzipiell gilt die Ordnung, die im Palettenfeld herrscht, ganz links oben, das Erdbeereis, kann also von einem beliebigen zugbegabten Spielstein erobert werden, waehrend die Bekanntschaft mit einer Zecke fast immer den Angreifer ins Jenseits schickt (mit Ausnahme der Spinnen, die Zecken fressen) Wichtig ist dann noch, dass der Hunter, der staerkste zugfaehige Stein, nur vom Devil geschlagen werden kann, waehrend der Devil gegen jeden anderen zugfaehigen Stein den Kuerzeren zieht) ---------------------------ICH WAR NOCH NIE SONDERLICH GUT---------------- ---------------------------BEIM ERKLAEREN, ABER FUERS ERSTE--------------- ---------------------------IST DAS ALLES, WAS MIR EINFAELLT---------------- Hoffentlich gefaellt dem einen oder anderen von Euch das Game, ich weiss, eine Menge Details waeren sicher noch zu verbessern, aber da hoffe ich auch auf Verbesserungsvorschlaege von Euch ----------------------------------------------------------------------------*/ // So und hier ist der Header, damit Ihr Euch in etwa vorstellen koennt, // wie die Architektur dieses Programmes aussieht // Wird an allen Ecken und Enden fuer Berechnungen benoetigt class Vektor{ public: short x,y; Vektor(); Vektor(short xx,short yy); bool operator==(Vektor Vergleich); Vektor operator-(); Vektor operator+(Vektor Summand); Vektor operator-(Vektor Minuend); short operator*(Vektor Faktor1); }; Vektor operator*(Vektor Faktor1,short Faktor2); // Ein Menge, in der mehrere Vektoren die Elemente sein koennen class Vektormenge{ unsigned Zuegezahl; // defensiver Programmierstil faengt schon damit an // dass man nicht einfach ueberall int hinschreibt, // wo Ganzzahlen benoetigt werden, sondern auch ueberlegt // ob die Werte ueberhaupt negativ sein koennen Vektor* Zuege; public: Vektormenge(); Vektormenge(const Vektormenge& zu_kopieren); ~Vektormenge(); bool AddZug(Vektor Hinzu); bool IsInside(Vektor Gesucht); unsigned GetZuegezahl(); // Liefert einen ganz speziellen Zug im Zuegearray zurueck // sollte erst nach Abfrage mit GetZuegezahl() aufgerufen // werden Vektor GetZug(unsigned ZugNummer); }; #include<windows.h> // Die (hoffentlich) massgeschneiderte Spielsteinklasse class Piece{ public: bool known; short besitzer; short value; Vektormenge* Zuegearray; // Speichert die Adresse einer Vektormenge // in der die fuer diesen Stein prinzipiell // moeglichen Zuege gespeichert sind HBITMAP* Ansichten[3]; UINT AnzahlAnsichten; char* my_Name; Piece(); // Gibt -1 zurueck, falls kein Zugarray initialisiert wurde, // ansonsten die Zahl der im Zugarray gespeicherten moeglichen // Zuege long GetMoveAmount(); // Befragt den Stein, ob er einen gewissen Zug // ausfuehren kann bool CanYouDo(Vektor Gefragt); // Liefert Eigenen Wert short GetValue(); }; // eine Feld ist eine Spezialisierung eines Vektors class Feld:public Vektor{ public: UINT Laenge; Piece** Hiesige_Steine; UINT maximal; UINT aktuell; HBITMAP* Falls_leer; HBITMAP* Es_geht_ab; HWND my_hwnd; Feld(); // nicht vergessen_baseID wird zum Zwecke der // Zugehoerigkeit zu Spielfeld oder Palettenfeld // vergeben (irgend ein vierstelliger Wert) // BITTE ERST AUFRUFEN, wenn die noetigen Werte // eingegeben wurden (geht leider nur muehsam // und manuell) bool Create(HINSTANCE hinst,HWND hpar,UINT baseID, UINT pixtoleft,UINT pixtoup); // Diese Funktion reserviert sogleich auch den // benoetigten Platz fuer die Zeiger auf die Steine // (wobei geplant ist, dass die Zeiger auch auf NULL // zeigen koennen)_Ausserdem zeigen alle Zeiger erstmal // auf NULL, das heisst, man kann nur einmal SetMaximal // aufrufen, um das Programm nicht durcheinander zu bringen bool SetMaximal(UINT maxkapaz); // Ein Aufruf dieser Funktion liefert true zurueck, wenn // das Uebernehmen des Steines geklappt hat (er also noch // Platz gehabt hat, ansonsten false), die Steine werden // uebereinander gestapelt bool UebernimmStein(Piece* NeuerStein); // Diese Funktion nimmt quasi den Stein von ganz oben vom // Stapel, d.h. setzt erstens den entsprechenden Zeiger auf // NULL, reduziert 'aktuell' wieder um 1 (sofern moeglich, // falls nicht: NULL-Zeiger retour. (!!! Wird der Rueckgabewert // nicht gespeichert, geht dem Spiel praktisch ein Spielstein // verloren !!! - UebernimmStein und SteinWegnehmen arbeiten wie // ein FILO Stapel zusammen) Piece* SteinWegnehmen(); // WENN ALLES KORREKT INITIALISIERT WURDE, DANN KANN ENDLICH // ZUM ERSTEN MAL DIE FUNKTION Draw() aufgerufen werden, // natuerlich weiss das Feld selbst, was wohin gezeichnet wer- // den soll, sonst haette ich mir ja die Mordsinitialisierungs- // funktion der Klasse MTactics gleich schenken koennen void Draw(bool spielt_sich_ab=false); }; // INNERHALB DER ANWENDUNGSKLASSE SPIELT SICH PRAKTISCH ALLES // AB, SIE IST DIE EIGENTUEMERIN UND OBERSTE VERWALTERIN DES // GESAMTEN PROGRAMMS, ein riesiger Container mit wenigen, // ziemlich grossen Funktionen, die dafuer aber auch entsprechend // maechtig sind class MTactics{ HINSTANCE hinzz; // Von Create erledigt HBITMAP verwendet[28]; // Von Create erledigt Vektormenge Zuegearray[3]; // Von Create erledigt Piece Steine[80]; // Von Create erledigt Feld Spielfeld[10][10],Palettenfeld[3][4]; // Von Create erledigt HWND vergrPlr,vergrCpu,plrText,cpuText; // Von Create erledigt HWND Startbutton,Palbutton,Qustartbutton; // Von Create erledigt HWND hauptfenster; // Von Create erledigt char stnamen[12][12]; // Von Create erledigt char no_selection[5]; // Von Create erledigt Vektor hilfsvektorarray[2][210]; // in [0] werden die Start- // felder gespeichert // in [1] die Zugehoerigen // Zielfelder short Spielphase; // 1 fuer Aufstellphase, 2 fuer Spielphase short NextPhase; // Mitunter benoetigt Piece* plrchosen; // In diesen Variablen werden Spielsteine Piece* cpuchosen; // gespeichert, die gerade ausgewaehlt // wurden Piece* winnerx; // Hier wird der Gewinner einer Begegnung zwischengespeichert Vektor Startfeld; // hier wird gespeichert, von wo der Spieler gestartet // ist, um spaeter einen Zug auf seine Zulaessigkeit // pruefen zu koennen. Falls -1/-1, dann gibt es noch kein // Startfeld Vektor Zielfeld; // Zur Zwischenspeicherung gedacht bool fuenfunbekannt; // Eine Variable, die die Fairness der KI sicherstellen // soll public: bool DoFast; // noetig, um die Bedienung des Games mit der Maus // etwas komfortabler zu gestalten WPARAM reserve; // Diese Funktion ist geradezu spektakulaer (einige hundert // Codezeilen) bool Create(HINSTANCE instanz,HWND hauptf); // Anzeigefunktion, die das gesamte Game auf dem Bildschirm abbilden kann, // wird aber nur ein einziges Mal, und zwar von Create, aufgerufen bool ShowAll(); // Diese Funktion wird auch nicht gerade simpel - Verarbeitet alle nur // denkbaren Mausklicks, die passieren koennen bool ProcessClick(WPARAM wParam); // Kuerzt die Aufstellprozedur ab bool QuickStart(); // Show_Selected kuemmert sich um die Anzeigen im // Vergroesserungsfenster sowie um die Texte darunter bool ShowSelected(); // Stelle Deine Figuren auf _ nach einem streng geheimen (lol) Algorithmus // stellt hier der Computer seine Steine auf, oder auch die des // Spielers, wenn der auf Quickstart geklickt hat bool CpuAufstellen(short addf=40); // Spieler_zieht() befasst sich mit dem Spielzug des Spielers // d.h. interpretiert die Mauseingaben und leitet entsprechend // an die Funktionen ZugMoeglich() und ExecuteMove() weiter bool Spieler_zieht(WPARAM wParam); // Computer_zieht() befasst sich mit der Berechnung des Computerzuges // das ist de facto die AI - Funktion, hat aber die beiden Helferlein // StrongAI() und FleeAI(), die sie unterstuetzen void Computer_zieht(); // Diese Funktion ueberprueft, ob die Aufstellung des Spielers zumindest // das Eis enthaelt, nur dann // wird das Spiel ueberhaupt gestartet, klasse Beispiel fuer Redundanz // extra kurze Funktion die so gut wie nie gebraucht wird bool Checkvalid(); // wichtige Funktion - Findet heraus, ob ein Zug mit einem Stein moeglich ist // - unter Beruecksichtigung der aktuellen Spielfeldsituation, da // sich zwar jede Fliege beispielsweise um den Vektor (9,0) prinzipiell // bewegen kann, koennte doch die Spielfeldbegrenzung oder ein Hindernis // dafuer sorgen, dass der Zug trotzdem nicht moeglich ist // Ein Zug, den diese Funktion fuer regelkonform befindet, kann getrost // zur spaeteren Beurteilung durch eine KI-Funktion gespeichert werden bool ZugMoeglich(Vektor,Piece*); // Funktion, die den angegebenen Zug ausfuehrt, sollte natuer- // lich nur Zuege in der Vektor Variablen erhalten, die zuvor // auf Zulaessigkeit ueberprueft wurden, um Zugriffe auf den // NULL Zeiger und dergleichen zu verhindern bool ExecuteMove(Vektor,Piece*); // Funktion, die sich wirklich starke Computerzuege einfallen laesst // gibt -1 zurueck, wenn nur noch schwache Zuege moeglich sind short StrongAI(short m); // Unterstuetzt das Programm dabei, angemessene Fluchtzuege zu machen, // wenn seine Steine angegriffen werden short FleeAI(short m); }; // Wird zum Control_ID vergeben benoetigt #define SPIELFELDID 1000 #define PALETTENFELDID 2000 #define PALBUTTONID 3000 #define VERGRCPUID 4000 #define VERGRHUMID 5000 #define VERGRPLRID 5000 #define TEXTCPUID 6000 #define TEXTPLRID 7000 #define TEXTSIZE 33 #define STARTBUTTONID 8000 #define EINZELFELDGROESSE 48 #define HUMPLR 1 #define CPUPLR 2 #define LARGESIZE 130 #define BUTTONSIZE 100 #define AUFSTELLZONE 6 #define QUICKSTARTID 9000
Und das Game selber koennt ihr dann von meiner Free Webspace Seite, die in meinem Profil steht, einfach herunterladen und ausprobieren, falls ihr immer noch daran zweifelt, dass viele Kommentare und die eine oder andere verschachtelte Schleife einem grossen Programm nur schaden können.
Viel Spass!
-
schonmal was von echten kosntanten in c++ gehört? nein? so langsam wundert mich hier gar nix mehr....
-
Shade Of Mine schrieb:
@Hume:
sorry, wenn ich jetzt Sachen nenne die schon genannt wurden, aber ich hab es nicht geschafft wirklich alle Posts durchzulesentypedef unsigned int UInt32; class bit_vec_int_set
Warum ist UInt32 groß und bit_vec_int_set klein?
Welchem Namensschema folgst du?Ich persönlich bevorzuge Camel-Case. Die Klasse ist allerdings Teil eines Projekts, dass dem Standard-C++ Schema folgt. Leider schaltet mein Gehirn immer mal wieder auf "automatik" und da wir bei dem Projekt keine gegenseitigen Reviews gemacht haben, ist da wohl zwischendurch immer mal wieder Camel-Case reingerutscht.
Shade Of Mine schrieb:
const unsigned char bits_set_in_byte_g[] =
Wäre das in einem unnamed namespace nicht besser aufgehoben?
Welchen Vorteil hätte das? Oder meinst du damit auch gleich Definition in der cpp-Datei?
Shade Of Mine schrieb:
void bit_vec_int_set::resize(UInt32 newMaxVal) { [...] }
Ich teile hier gerne in grow() und shrink() auf.
Guter Punkt.
Shade Of Mine schrieb:
Ohne zu wissen was test() macht
test(i) liefert 0, falls i nicht Element der Menge und hat seinen Namen, weil es testet ob das zu i passende Bit gesetzt ist oder nicht.
Es wäre sicher einfacher, wenn ich remove und insert über find() implementieren würde und nicht über das low-level test().Shade Of Mine schrieb:
bit_vec_int_set bit_vec_int_set::getUnion(const bit_vec_int_set& other) const { const bit_vec_int_set& smallerSet = words_ < other.words_ ? *this : other; const bit_vec_int_set& largerSet = &smallerSet == this ? other : *this; bit_vec_int_set newSet(largerSet); newSet.unite(smallerSet); return newSet; }
Cool. Das habe ich mir gestern nachdem ich den Code gepostet hatte (und damit seit einem halben Jahr zum ersten Mal wieder draufgeschaut habe) auch als
erstes gedacht.
-
Mecnels schrieb:
Bitte, ein Beispiel für eine gelungene Architektur eines etwas größeren Projektes, das, wie ich meine, auch sehr gut gelungen ist (trotz tief geschachtelter Schleifen) koennt ihr an diesem Header erkennen [...]
Hoi,
ich rate dir _dringend_, statt #define const und enum zu benutzen. Außerdem würde ich keine rohen Arrays und Zeiger verwenden.
Vektormenge* Zuegearray
Sowas ist einfach ganz böse und immer wieder schuld an late-night-debugging-sessions.
Versuch statt dessen lieber std::vector oder boost::array und setzt dir noch eine Indexprüfung in den op[].Die Signaturen für die Operatoren '+' und '-' sind schlicht falsch. Ein Buch, was mir diesbzgl. sehr auf die Sprünge geholfen hat, ist "Effektiv C++ programmieren" von Scott Meiers. Sehr lesenswert.
-
Mecnels schrieb:
// Wird an allen Ecken und Enden fuer Berechnungen benoetigt class Vektor{ //... }
Uninteressant...
Daher, dass Vektor ein abstrakter Begriff ist, solltest du betonen, dass du einen geometrischen meinst.// defensiver Programmierstil faengt schon damit an // dass man nicht einfach ueberall int hinschreibt, // wo Ganzzahlen benoetigt werden, sondern auch ueberlegt // ob die Werte ueberhaupt negativ sein koennen
Ist das ein Statement für uns oder steht das wirklich so im Quelltext?
Was soll die Klasse Vektormenge? Ein schlecht implementierter Container???
#include <windows.h>
Gehört ganz oben hin.
Zu der Piece-Klasse:
Wieso immer die antiquierte Trennung von Array und Arraygröße? Wieso nicht gleich ein Container?
Außerdem sind die Hälfte der Kommentare nutzlos.Piece** Hiesige_Steine;
Die Funktionsbeschreibungen sind Romane ("bitte", "nicht vergessen",...)...
// ein riesiger Container mit wenigen, // ziemlich grossen Funktionen, die dafuer aber auch entsprechend // maechtig sind
aha.
[....]
Deine Namenskonventionen sind lustig. Mal deutsch, mal englisch, mal gemischt.
// Wird zum Control_ID vergeben benoetigt #define SPIELFELDID 1000 #define PALETTENFELDID 2000 #define PALBUTTONID 3000 #define VERGRCPUID 4000 #define VERGRHUMID 5000 #define VERGRPLRID 5000 #define TEXTCPUID 6000 #define TEXTPLRID 7000 #define TEXTSIZE 33 #define STARTBUTTONID 8000 #define EINZELFELDGROESSE 48 #define HUMPLR 1 #define CPUPLR 2 #define LARGESIZE 130 #define BUTTONSIZE 100 #define AUFSTELLZONE 6 #define QUICKSTARTID 9000
#defines sind böse, nimm Konstanten. Außerdem gehören die ganz oben hin.
-
simon.phoenix schrieb:
...ist ein Mythos der sich in 20 Jahren OOP nicht bewahrheitet hat. Die Annahme OOP = Wiederverwendbar ist in der Praxis schlicht und einfach falsch.
Ein Grund: Die allerwenigsten Klassen sind einsame Inseln die ohne Kontext eingesetzt werden können. Vielmehr ermutigt einen die OOP ja dazu, Programme als Kolaboration von Objekten zu implementieren.
Auf der anderen Seite bieten die OO-Mittel von C++ aber keinerlei Möglichkeiten benötigten Kontext in programmlesbarer Form explizit zu spezifizieren.
Das führt dann dazu, dass sich "einfache" Klassen wie Container andere reine Value-Types einfach wiederverwenden lassen, da sie keinerlei spezielle Abhängigkeiten besitzen. Die Wiederverwendung von Domainabstraktionen artet hingegen meist in eine ewige Fummelarbeit aus in der Abhängigkeiten mühsam Stück für Stück herausgearbeitet und in Form von z.B. Interfaces sichtbar gemacht werden müssen.
Wenn du dann noch Domain-Details im Code fest verdrahtest hast, ist meist alles aus, da genau solche Details gerade von Projekt zu Projekt unterscheiden. D.h. selbst wenn du in den sauren Apfel beist und neben einem Foo gleich auch noch ein Fred, Heinz und Karl in deinem neuen Projekt aktzeptierst (obwohl du eigentlich nur Foo brauchst), garantiert dir keiner, dass die für Foo in Projekt X getroffenen Annahmen in Projekt Y immernoch gelten. Hier die nötige Flexibilität zu erlauben erfordert viel arbeit und kommt keinesfalls alleine. Das ist also kein Nebenprodukt, dass dank OOP abfällt.Das ist ja z.B. genau der Punkt wo die Komponentenorientierung punkten will (z.B. CORBA Komponenten usw.) Hier versucht man die Abhängigkeiten in Metadaten zu verpacken und dadurch eine Wiederverwendung zumindestens auf Komponentenebene (meist mehr als eine einzelne Klasse) zu erlangen.
Es gibt noch viele andere Gründe warum die Gleichung OOP = gute Wiederverndbarkeit nicht automatisch aufgeht. Die Tatsache ist auf jeden Fall durch Zahlen belegt (einige Sachen findet man z.B. in McConnells "Code Complete") und Gründe dafür kann man eigentlich in jedem neueren OOP-Buch nachlesen. Eine Suche im Netz liefert ebenfalls viele Hinweise.
-
Danke Hume für die Erklärung. Muss da wohl etwas von meiner blauäugigen Ansicht abrücken
D.h. man verwendet OOP einfach, erwartet aber kein Allheilmittel von ihr? Oder h.d. es ist egal ob man prozedural oder objektorientiert programmiert :p?
-
Mecnels schrieb:
Und das Game selber koennt ihr dann von meiner Free Webspace Seite, die in meinem Profil steht, einfach herunterladen und ausprobieren, falls ihr immer noch daran zweifelt, dass viele Kommentare und die eine oder andere verschachtelte Schleife einem grossen Programm nur schaden können.
LOL, groß? Das ist nicht groß! Groß fängt für mich bei > 10000 LOC an.
-
MaSTaH schrieb:
LOL, groß? Das ist nicht groß! Groß fängt für mich bei > 10000 LOC an.
LOL, groß? Das ist nicht groß! Groß fängt für mich bei > 100000 LOC an.
-
Gregor schrieb:
MaSTaH schrieb:
LOL, groß? Das ist nicht groß! Groß fängt für mich bei > 10000 LOC an.
LOL, groß? Das ist nicht groß! Groß fängt für mich bei > 100000 LOC an.
LOL, groß? Das ist nicht groß! Groß fängt für mich bei > 1000000 LOC an.
-
Gregor schrieb:
MaSTaH schrieb:
LOL, groß? Das ist nicht groß! Groß fängt für mich bei > 10000 LOC an.
LOL, groß? Das ist nicht groß! Groß fängt für mich bei > 100000 LOC an.
Deswegen habe ich ja gesagt "fängt an"
. Ich habe meist keinen Einblick in das komplette Projekt und dementsprechend kann ich auch nicht schätzen wieviele LOC es insgesamt beherbergt. Ich habe nur mal grob geschätzt wieviel in meiner aktuellen Library mittlerweile schon so angefallen sein könnte. Steckt noch in den Kinderschuhen, aber ich würde sie schon jetzt als groß (besser gesagt umfangreich) bezeichnen.
-
// Wird an allen Ecken und Enden fuer Berechnungen benoetigt
Unnötiger Kommentar. Sagt nämlich nichts aus. Ich weiss jetzt nur
Vektor ist wichtig, aber warum es dass ich, weiss ich nicht.
Und was es ist auch nicht.class Vektor{ public: short x,y; Vektor(); Vektor(short xx,short yy); bool operator==(Vektor Vergleich); Vektor operator-(); Vektor operator+(Vektor Summand); Vektor operator-(Vektor Minuend); short operator*(Vektor Faktor1); };
diese operatoren sollten (mit ausnahme des unären -) non member funktionen sein.
// Ein Menge, in der mehrere Vektoren die Elemente sein koennen
Da fällt mir sofort auf: was macht Vecktormenge besser als std::vector ?
Warum kein standard Container?bool AddZug(Vektor Hinzu);
Was macht das bool? true/false bei success fehlschlagen?
Dafür haben wir exception...bool IsInside(Vektor Gesucht);
wäre find() nicht vielleicht besser?
und sollte es nicht vielleicht const sein?warum aufeinmal englisch?
unsigned GetZuegezahl();
wäre das hier const nicht vielleicht besser?
Vektor GetZug(unsigned ZugNummer);
Wäre dafür der op[] nicht besser geeignet? Und const wäre es auch nicht schlecht.
Vektormenge* Zuegearray; // Speichert die Adresse einer Vektormenge // in der die fuer diesen Stein prinzipiell // moeglichen Zuege gespeichert sind
warum ein zeiger?
// eine Feld ist eine Spezialisierung eines Vektors
unnötiger kommentar. Aber was ist ein Feld und _warum_ ist es
die Spezialisierung eines vektors?Piece** Hiesige_Steine;
Wäre hier ein Container nicht angebracht?
Zeiger auf Zeiger sind oft sehr häßlich zu verwenden...HBITMAP* Falls_leer; HBITMAP* Es_geht_ab;
Namen sagen mir garnichts.
// nicht vergessen_baseID wird zum Zwecke der // Zugehoerigkeit zu Spielfeld oder Palettenfeld // vergeben (irgend ein vierstelliger Wert) // BITTE ERST AUFRUFEN, wenn die noetigen Werte // eingegeben wurden (geht leider nur muehsam // und manuell)
Klingt übel und klingt nach refactoring
// Diese Funktion reserviert sogleich auch den // benoetigten Platz fuer die Zeiger auf die Steine // (wobei geplant ist, dass die Zeiger auch auf NULL // zeigen koennen)_Ausserdem zeigen alle Zeiger erstmal // auf NULL, das heisst, man kann nur einmal SetMaximal // aufrufen, um das Programm nicht durcheinander zu bringen
Klingt auch übel. Klingt sehr nach schwer zu findenden Bug wenn man
es doch tut.
Und klingt auch nach: der name SetMaximal passt einfach nicht.// Diese Funktion nimmt quasi den Stein von ganz oben vom // Stapel, d.h. setzt erstens den entsprechenden Zeiger auf // NULL, reduziert 'aktuell' wieder um 1 (sofern moeglich, // falls nicht: NULL-Zeiger retour. (!!! Wird der Rueckgabewert // nicht gespeichert, geht dem Spiel praktisch ein Spielstein // verloren !!! - UebernimmStein und SteinWegnehmen arbeiten wie // ein FILO Stapel zusammen)
Klingt echt kompliziert und bug anfällig.
// WENN ALLES KORREKT INITIALISIERT WURDE, DANN KANN ENDLICH // ZUM ERSTEN MAL DIE FUNKTION Draw() aufgerufen werden, // natuerlich weiss das Feld selbst, was wohin gezeichnet wer- // den soll, sonst haette ich mir ja die Mordsinitialisierungs- // funktion der Klasse MTactics gleich schenken koennen void Draw(bool spielt_sich_ab=false);
Der Parameter ist mir nicht klar
Und ein enormer Aufwand bis ich Draw() aufrufen kann, ist das auch.Sollte man vielleicht etwas vereinfachen...
// INNERHALB DER ANWENDUNGSKLASSE SPIELT SICH PRAKTISCH ALLES // AB, SIE IST DIE EIGENTUEMERIN UND OBERSTE VERWALTERIN DES // GESAMTEN PROGRAMMS, ein riesiger Container mit wenigen, // ziemlich grossen Funktionen, die dafuer aber auch entsprechend // maechtig sind
Hilft mir nicht viel um zu verstehen was da abgeht.
Wenn ich eine Klasse sehe, gehe ich immer davon aus, dass sie wichtig ist...
HINSTANCE hinzz; // Von Create erledigt HBITMAP verwendet[28]; // Von Create erledigt Vektormenge Zuegearray[3]; // Von Create erledigt Piece Steine[80]; // Von Create erledigt Feld Spielfeld[10][10],Palettenfeld[3][4]; // Von Create erledigt HWND vergrPlr,vergrCpu,plrText,cpuText; // Von Create erledigt HWND Startbutton,Palbutton,Qustartbutton; // Von Create erledigt HWND hauptfenster; // Von Create erledigt char stnamen[12][12]; // Von Create erledigt char no_selection[5]; // Von Create erledigt Vektor hilfsvektorarray[2][210]; // in [0] werden die Start- // felder gespeichert // in [1] die Zugehoerigen // Zielfelder short Spielphase; // 1 fuer Aufstellphase, 2 fuer Spielphase short NextPhase; // Mitunter benoetigt Piece* plrchosen; // In diesen Variablen werden Spielsteine Piece* cpuchosen; // gespeichert, die gerade ausgewaehlt // wurden Piece* winnerx; // Hier wird der Gewinner einer Begegnung zwischengespeichert Vektor Startfeld; // hier wird gespeichert, von wo der Spieler gestartet // ist, um spaeter einen Zug auf seine Zulaessigkeit // pruefen zu koennen. Falls -1/-1, dann gibt es noch kein // Startfeld Vektor Zielfeld; // Zur Zwischenspeicherung gedacht bool fuenfunbekannt; // Eine Variable, die die Fairness der KI sicherstellen // soll public: bool DoFast; // noetig, um die Bedienung des Games mit der Maus // etwas komfortabler zu gestalten WPARAM reserve;
Bo ey. Soviele Variablen, teils Zeiger teils nicht. Und ein paar wahnsinns arrays.
Ne, die Klasse will ich nicht warten müssen...bool Create(HINSTANCE instanz,HWND hauptf);
Warum eigentlich immer Create() und nicht im Ctor?
// Anzeigefunktion, die das gesamte Game auf dem Bildschirm abbilden kann, // wird aber nur ein einziges Mal, und zwar von Create, aufgerufen bool ShowAll();
Was liefert sie denn zurück? Und warum ist sie public wenn nur Create sie aufrufen darf?
// Kuerzt die Aufstellprozedur ab bool QuickStart();
??
sagt mir garnix. und was macht das bool?// Stelle Deine Figuren auf _ nach einem streng geheimen (lol) Algorithmus // stellt hier der Computer seine Steine auf, oder auch die des // Spielers, wenn der auf Quickstart geklickt hat bool CpuAufstellen(short addf=40);
wasmacht addf?
// Computer_zieht() befasst sich mit der Berechnung des Computerzuges // das ist de facto die AI - Funktion, hat aber die beiden Helferlein // StrongAI() und FleeAI(), die sie unterstuetzen void Computer_zieht();
Eine ganze AI in 3 funktionen... Ist sicher riesig.
// Diese Funktion ueberprueft, ob die Aufstellung des Spielers zumindest // das Eis enthaelt, nur dann // wird das Spiel ueberhaupt gestartet, klasse Beispiel fuer Redundanz // extra kurze Funktion die so gut wie nie gebraucht wird bool Checkvalid();
Eis?
#define SPIELFELDID 1000 #define PALETTENFELDID 2000 #define PALBUTTONID 3000 #define VERGRCPUID 4000 #define VERGRHUMID 5000 #define VERGRPLRID 5000 #define TEXTCPUID 6000 #define TEXTPLRID 7000 #define TEXTSIZE 33 #define STARTBUTTONID 8000 #define EINZELFELDGROESSE 48 #define HUMPLR 1 #define CPUPLR 2 #define LARGESIZE 130 #define BUTTONSIZE 100 #define AUFSTELLZONE 6 #define QUICKSTARTID 9000
Schonmal was von const gehört?
-
Shade Of Mine schrieb:
diese operatoren sollten (mit ausnahme des unären -) non member funktionen sein.
Jetzt enttäuscht Du mich aber ein bisschen. Erklär mir bitte wie Du einen Skalar zu einem Vektor hinzuaddieren willst? Das ist gar nicht definiert, und um zu verhindern, dass Konvertierungskonstruktoren hier Unsinn anrichten können, sollte man gerade bei Vektoraddition oder Subtraktion KEINE globalen Funktionen definieren, sondern ausschließlich Elementfunktion. Das ist ja so elementar. Globale Operatoren machen zum Beispiel bei Klassen für komplexe oder rationale Zahlen Sinn, weil hier tatsächlich des öfteren Ganzzahlen zu Dupeln addiert werden, sodass Konvertierungskonstruktoren auch keinen Schaden anrichten können. Aber sowas wie Ganzzahl + Vektor ist total unsinnig und rechtfertigt in jedem Fall die Implementierung der Operators + als Elementfunktion.
-
Hallo,
wenn du nicht willst, dass eine Ganzzahl implizit zu einem Vektor wird, dann mach die Konstruktoren explicit.
Sprich: wenn du Angst vor den Auswirkungen eines Konvertierungsctors hast, dann sorg dafür, dass es keinen solchen Ctors gibt. C++ hat nicht umsonst dafür extra ein Schlüsselwort.
Irgendwie tendierst du dazu die Pferde von der falschen Seite aufzuzäumen.
-
Dann werf ich euch Haien auch noch ein Stücklein Code zum Frass vor.
Die Klasse, in Java, interpretiert Elemente eines Textes, als wären es Componenten (Buttons + etc.) auf einer GUI, und verschickt an spezielle Listener Events, wenn der Benutzer mit der Maus rumspielt.
(Aufmerksame Beobachter mögen erkennen, dass der Code noch nicht sehr alt ist, einige Kommentare fehlen noch)
Was mich bewegt den Code zu posten? Ich denke er ist gut genug geschrieben, dass man ihn an verschiedenen Orten einsetzen kann, und auch eine Erweiterung möglich ist.
[Edit: und ich bin interessiert, was ihr davon haltet]/* * Created on 09.01.2005 */ package bibliothek2.gui.text; /** * Dieser Listener wird einem {@link bibliothek2.gui.text.EditorGuard EditorGuard} * hinzugefügt, und von dem Guard von Veränderungen unterrichtet.<br> * Die Methoden dieses Interfaces sind dem {@link java.awt.event.MouseListener MouseListener} * und dem {@link java.awt.event.MouseMotionListener MouseMotionListener} * nachempfunden, und werden auch entsprechend genutzt. * * @author Benjamin Sigg */ public interface EditorListener{ public void mouseMoved( EditorEvent event ); public void mouseClicked( EditorEvent event ); public void mouseExited( EditorEvent event ); public void mouseEntered( EditorEvent event ); public void mouseDragged( EditorEvent event ); public void mousePressed( EditorEvent event ); public void mouseReleased( EditorEvent event ); }
/* * Created on 09.01.2005 */ package bibliothek2.gui.text; import java.awt.event.MouseEvent; import javax.swing.text.Element; /** * Ein EditorEvent dient als Übertragung von Informationen von einem * {@link EditorGuard} zu einem {@link EditorListener}. * * @author Benjamin Sigg */ public class EditorEvent{ /** * Information, wohin dieses Event ursprünglich geschickt wurde. * Z.b. sollte ein CLICKED-Event an {@link EditorListener#mouseClicked(EditorEvent)} * geschickt werden. */ public enum Typ{ CLICKED, EXITED, ENTERED, MOVED, DRAGGED, PRESSED, RELEASED }; private Typ typ; private MouseEvent origin; private EditorGuard source; private Element element; /** * Standardkonstruktor * @param source Der Guard, welcher das Event auslöst * @param element Das Element, welches betroffen ist * @param origin Das MouseEvent, welches zu dem verschicken dieses Eventes * geführt hat * @param typ Der Typ des Events */ public EditorEvent( EditorGuard source, Element element, MouseEvent origin, Typ typ ){ this.typ = typ; this.origin = origin; this.source = source; this.element = element; } /** * Gibt das Element zurück, für welches das Event geworfen wurde. * @return das Element */ public Element getElement() { return element; } /** * Gibt das MouseEvent zurück, welches zum Auslöser dieses Events wurde * @return Der Auslöser */ public MouseEvent getOrigin() { return origin; } /** * Gibt den EditorGuard zurück, welcher dieses Event verschickt hat. * @return Der Gaurd */ public EditorGuard getSource() { return source; } /** * Gibt den Typ dieses Eventes zurück. * @return Der Typ */ public Typ getTyp() { return typ; } public String toString(){ return getClass().getName() + " [typ= " + typ + ", element= " + element + ", source= " + source + ", origin= " + origin + "]"; } }
/* * Created on 09.01.2005 */ package bibliothek2.gui.text; import java.awt.Point; import java.awt.Rectangle; import java.awt.Shape; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.util.Vector; import javax.swing.JEditorPane; import javax.swing.plaf.TextUI; import javax.swing.text.BadLocationException; import javax.swing.text.Document; import javax.swing.text.Element; import javax.swing.text.Position; /** * Der EditorGuard überwacht die Mausbewegungen über einem * {@link javax.swing.JEditorPane JEditorPane} und verschickt Events, sollte * der Benutzer ein {@link javax.swing.text.Element Element} klichen, es * überfahren, oder andere Mausaktionen machen.<br> * Der EditorGuard kann immer nur ein EditorPane überwachen. * * @see bibliothek2.gui.text.EditorListener EditorListener * @see bibliothek2.gui.text.EditorEvent EditorEvent * * @author Benjamin Sigg */ public class EditorGuard{ private Element element; private JEditorPane editor; private Listener listener; private Vector<EditorListener> listeners = new Vector<EditorListener>(); public EditorGuard(){ listener = createListener(); } public EditorGuard( JEditorPane editor ){ this(); setEditor( editor ); } public void addEditorListener( EditorListener listener ){ listeners.add( listener ); } public void removeEditorListener( EditorListener listener ){ listeners.remove( listener ); } /** * Setzt den zu überwachenden Editor. * @param editor Der neue Editor */ public void setEditor( JEditorPane editor ){ if( this.editor != null ){ this.editor.removeMouseListener( listener ); this.editor.removeMouseMotionListener( listener ); } this.editor = editor; if( editor != null ){ editor.addMouseListener( listener ); editor.addMouseMotionListener( listener ); } listener.reset(); } /** * Gibt das JEditorPane zurück, welches von diesem Guard überwacht wird. * @return Der Editor oder null, sollte kein Editor gesetzt sein */ public JEditorPane getEditor(){ return editor; } /** * Generiert einen Listener. Dieser Listener wird den JEditorPanes hinzugefügt. * @return Der neue Listener */ protected Listener createListener(){ return new Listener(); } /** * Gibt dasjenige Element zurück, auf das sich derzeit alle verschickten * Events beziehen. * @return Das Element, auf das sich alle Events beziehen. */ public Element getElement(){ return element; } /** * Setzt das Element, auf das sich alle durch <code>fireX</code> verschickten * Events beziehen. * @param element Das Element */ protected void setElement( Element element ){ this.element = element; } /** * Nicht jedes Element ist interessant genug um ein Event zu verschicken. * Diese Methode entscheidet, für welche Elemente Events versendet werden. * @param element Das zu prüfende Element * @return true, wenn Events dieses Element betreffend verschickt * werden soll */ protected boolean isInteresting( Element element ){ return true; } /** * Gibt dasjenige Element zurück, welches auf dem JEditorPane dieses * Guards, an den angegebenen Koordinaten x/y liegt. * @param x Die x-Koordinaten * @param y Die y-Koordinaten * @return Das Element oder null, sollte sich an den angegebenen Koordinaten * kein Element befinden, oder falls kein Editor gesetzt ist. */ public Element getElement( int x, int y ){ if( editor == null ) return null; if( !editor.getVisibleRect().contains( x, y ) ) return null; Document document = editor.getDocument(); Point location = new Point( x, y ); int offset = editor.viewToModel( location ); Element element = getElement( offset, document ); if( elementContainsLocation( editor, element, location )) return element; else return null; } /** * Sucht in dem Document dasjenige Element, dessen Grenzen das offset * umschliessen.<br> * Die Defaultimplementation untersucht dazu nur das DefaultRootElement. * @param offset Die gesuchte Position im Document * @param document Das zu untersuchende Document * @return Das Element */ public Element getElement( int offset, Document document ){ Element element = document.getDefaultRootElement(); while( !element.isLeaf() ){ int index = element.getElementIndex( offset ); element = element.getElement( index ); } return element; } /** * Überprüft ob an dem Punkt <code>location</code> auf dem JEditorPane * <code>editor</code> das Element <code>element</code> angezeigt wird. * @param editor Der Editor, auf dem das Element angezeigt wird * @param element Das Element * @param location Der Punkt im Koordinatensystem von editor * @return true, wenn das Element den Punkt beinhaltet, false andernfalls */ public boolean elementContainsLocation( JEditorPane editor, Element element, Point location ){ try { TextUI ui = editor.getUI(); Shape begin = ui.modelToView( editor, element.getStartOffset(), Position.Bias.Forward ); if ( begin == null) { return false; } Rectangle bounds = (begin instanceof Rectangle) ? (Rectangle)begin : begin.getBounds(); Shape end = ui.modelToView( editor, element.getEndOffset(), Position.Bias.Backward); if (end != null) { Rectangle endBounds = (end instanceof Rectangle) ? (Rectangle)end : end.getBounds(); bounds.add( endBounds ); } return bounds.contains( location.x, location.y ); } catch (BadLocationException ex) { return false; } } /** * Schickt dieses Event an die dafür vorgesehene Methode der Listener ab. * @param event Das zu verschickende Event */ protected void fireEvent( EditorEvent event ){ EditorListener[] listeners = this.listeners.toArray( new EditorListener[ this.listeners.size() ] ); EditorEvent.Typ typ = event.getTyp(); if( typ == EditorEvent.Typ.CLICKED ) for( EditorListener listener : listeners ) listener.mouseClicked( event ); else if( typ == EditorEvent.Typ.DRAGGED ) for( EditorListener listener : listeners ) listener.mouseDragged( event ); else if( typ == EditorEvent.Typ.ENTERED ) for( EditorListener listener : listeners ) listener.mouseEntered( event ); else if( typ == EditorEvent.Typ.EXITED ) for( EditorListener listener : listeners ) listener.mouseExited( event ); else if( typ == EditorEvent.Typ.MOVED ) for( EditorListener listener : listeners ) listener.mouseMoved( event ); else if( typ == EditorEvent.Typ.PRESSED ) for( EditorListener listener : listeners ) listener.mousePressed( event ); else if( typ == EditorEvent.Typ.RELEASED ) for( EditorListener listener : listeners ) listener.mouseReleased( event ); else throw new IllegalArgumentException( "unknown typ: " + typ ); } /** * Ruft die {@link EditorListener#mouseClicked(EditorEvent) mouseClicked}-Methode * aller registrierter EditorListener auf. * @param origin Das Event, welches die Aktion auslöste */ protected void fireMouseClicked( MouseEvent origin ){ fireEvent( new EditorEvent( this, element, origin, EditorEvent.Typ.CLICKED ) ); } /** * Ruft die {@link EditorListener#mouseMoved(EditorEvent) mouseMoved}-Methode * aller registrierter EditorListener auf. * @param origin Das Event, welches die Aktion auslöste */ protected void fireMouseMoved( MouseEvent origin ){ fireEvent( new EditorEvent( this, element, origin, EditorEvent.Typ.MOVED ) ); } /** * Ruft die {@link EditorListener#mouseExited(EditorEvent) mouseExited}-Methode * aller registrierter EditorListener auf. * @param origin Das Event, welches die Aktion auslöste */ protected void fireMouseExited( MouseEvent origin ){ fireEvent( new EditorEvent( this, element, origin, EditorEvent.Typ.EXITED ) ); } /** * Ruft die {@link EditorListener#mouseEntered(EditorEvent) mouseEntered}-Methode * aller registrierter EditorListener auf. * @param origin Das Event, welches die Aktion auslöste */ protected void fireMouseEntered( MouseEvent origin ){ fireEvent( new EditorEvent( this, element, origin, EditorEvent.Typ.ENTERED ) ); } /** * Ruft die {@link EditorListener#mouseDragged(EditorEvent) mouseDragged}-Methode * aller registrierter EditorListener auf. * @param origin Das Event, welches die Aktion auslöste */ protected void fireMouseDragged( MouseEvent origin ){ fireEvent( new EditorEvent( this, element, origin, EditorEvent.Typ.DRAGGED ) ); } /** * Ruft die {@link EditorListener#mousePressed(EditorEvent) mousePressed}-Methode * aller registrierter EditorListener auf. * @param origin Das Event, welches die Aktion auslöste */ protected void fireMousePressed( MouseEvent origin ){ fireEvent( new EditorEvent( this, element, origin, EditorEvent.Typ.PRESSED ) ); } /** * Ruft die {@link EditorListener#mouseReleased(EditorEvent) mouseReleased}-Methode * aller registrierter EditorListener auf. * @param origin Das Event, welches die Aktion auslöste */ protected void fireMouseReleased( MouseEvent origin ){ fireEvent( new EditorEvent( this, element, origin, EditorEvent.Typ.RELEASED ) ); } /** * Der Listener überwacht die Bewegung der Maus, und leitet die Events * weiter. */ protected class Listener implements MouseListener, MouseMotionListener{ /** * Die Anzahl gedrückter Maustasten<br> * Wenn diese Zahl grösser als 0 ist, sollten sich alle Events * auf das gespeicherte Element beziehen, und es sollte kein * neues Element untersucht werden. */ protected int pressCount = 0; /** * Das Element das sich unter der Maus befindet, während sie im * "drag"-Zustand ist. */ protected Element dragElement = null; /** * Wird von dem Guard aufgerufen wenn ein neues JEditorPane gesetzt * wird. Der Listener sollte danach wieder ein Verhalten haben, als * wäre keine Maustaste gedrückt.<br> * Wird die Methode überschrieben, wird ein Aufruf durch * <code>super.reset()</code> empfohlen. */ public void reset(){ pressCount = 0; } public void mouseClicked( MouseEvent e ) { Element element = getElement( e.getX(), e.getY() ); setElement( element ); if( element != null && isInteresting( element )) fireMouseClicked( e ); } public void mousePressed( MouseEvent e ) { if( pressCount == 0 ){ element = getElement( e.getX(), e.getY() ); dragElement = element; } pressCount++; if( element != null && isInteresting( element )) fireMousePressed( e ); } public void mouseReleased( MouseEvent e ) { pressCount = Math.max( 0, pressCount-1 ); if( element != null && isInteresting( element )) fireMouseReleased( e ); if( pressCount == 0 ){ Element newElement = dragElement; if( newElement != element ){ if( element != null && isInteresting( element )) fireMouseExited( e ); setElement( newElement ); if( element != null && isInteresting( element )) fireMouseEntered( e ); } } } public void mouseEntered( MouseEvent e ) { if( pressCount == 0 ){ setElement( getElement( e.getX(), e.getY() ) ); if( element != null && isInteresting( element )) fireMouseEntered( e ); } else{ dragElement = getElement( e.getX(), e.getY() ); if( dragElement != null && isInteresting( dragElement )) fireEvent( new EditorEvent( EditorGuard.this, dragElement, e, EditorEvent.Typ.ENTERED )); } } public void mouseExited( MouseEvent e ) { if( element != null && isInteresting( element )) fireMouseExited( e ); if( pressCount == 0 ) setElement( null ); else{ if( dragElement != null && isInteresting( dragElement )) fireEvent( new EditorEvent( EditorGuard.this, dragElement, e, EditorEvent.Typ.EXITED )); dragElement = null; } } public void mouseDragged( MouseEvent e ) { Element newElement = getElement( e.getX(), e.getY() ); if( element != null && isInteresting( element )) fireMouseDragged( e ); if( newElement != dragElement ){ if( dragElement != null && isInteresting( dragElement )){ fireEvent( new EditorEvent( EditorGuard.this, dragElement, e, EditorEvent.Typ.EXITED )); } dragElement = newElement; if( dragElement != null && isInteresting( dragElement )) fireEvent( new EditorEvent( EditorGuard.this, dragElement, e, EditorEvent.Typ.ENTERED )); } } public void mouseMoved( MouseEvent e ) { Element newElement = getElement( e.getX(), e.getY() ); if( newElement != element ){ if( element != null && isInteresting( element )){ fireMouseMoved( e ); fireMouseExited( e ); } setElement( newElement ); if( element != null && isInteresting( element )){ fireMouseEntered( e ); fireMouseMoved( e ); } } else if( element != null && isInteresting( element )) fireMouseMoved( e ); } } }
Guten Apetit
-
Jetzt mal eine ehrlich gemenínte Frage: habt ihr jetzt nur kommentare hinzugefügt oder standen die vo anfang an da. Wenn das nämlich so ist sollte ich meinen "Kommentierungsstil" schnell ändern...
-
Mecnels schrieb:
Das ist gar nicht definiert, und um zu verhindern, dass Konvertierungskonstruktoren hier Unsinn anrichten können, sollte man gerade bei Vektoraddition oder Subtraktion KEINE globalen Funktionen definieren, sondern ausschließlich Elementfunktion. Das ist ja so elementar. Globale Operatoren machen zum Beispiel bei Klassen für komplexe oder rationale Zahlen Sinn, weil hier tatsächlich des öfteren Ganzzahlen zu Dupeln addiert werden, sodass Konvertierungskonstruktoren auch keinen Schaden anrichten können. Aber sowas wie Ganzzahl + Vektor ist total unsinnig und rechtfertigt in jedem Fall die Implementierung der Operators + als Elementfunktion.
Hume hat es perfekt erklärt warum dein Ansatz etwas ungewöhnlich ist.
Und was sagst du zu meiner anderen Kritik? Oder hast du gute Argumente warum explicit hier beim Ctor nicht angebracht wäre, etc.
Ich bin gerne bereit offen zu diskutieren.
-
ness schrieb:
Jetzt mal eine ehrlich gemenínte Frage: habt ihr jetzt nur kommentare hinzugefügt oder standen die vo anfang an da. Wenn das nämlich so ist sollte ich meinen "Kommentierungsstil" schnell ändern...
Ich schreibe wenig Kommentare, aber viel Dokumentation. Das ist einfach schlechte Erfahrung mit zuwenig Dokumentation... das dort oben ist mein üblicher Dokumentierstil.
-
ness schrieb:
Jetzt mal eine ehrlich gemenínte Frage: habt ihr jetzt nur kommentare hinzugefügt oder standen die vo anfang an da. Wenn das nämlich so ist sollte ich meinen "Kommentierungsstil" schnell ändern...
Dokumentieren tue ich eigentlich immer ganz gut, wenn ich nicht gerade besonders schlecht gelaunt bin. Meisten reifen die Doc-Kommentare dann auch erst im Laufe der Zeit richtig aus, weswegen z.B. Shade gleich mal entdeckt hat, dass mein file kein Dateiname, sondern ein Pfad zu einer Datei ist.
Mit der Zeit finde ich solche Sachen dann und bessere sie aus.Kommentare im Source findet man bei mir eh nur spärlich, ich hab jetzt sogar einige noch raus, seit dem ich das gepostet habe - zu trivial.
-
also das einzige was mich an mecnels code wirklich stört ist das er deutsch und englisch mischt. das macht einen ja kirre wenn man sich das anguckt
und zu JBeni
/** * Gibt dasjenige Element zurück, auf das sich derzeit alle verschickten * Events beziehen. * @return Das Element, auf das sich alle Events beziehen. */ public Element getElement(){ return element; } /** * Setzt das Element, auf das sich alle durch <code>fireX</code> verschickten * Events beziehen. * @param element Das Element */ protected void setElement( Element element ){ this.element = element; } /** * Nicht jedes Element ist interessant genug um ein Event zu verschicken. * Diese Methode entscheidet, für welche Elemente Events versendet werden. * @param element Das zu prüfende Element * @return true, wenn Events dieses Element betreffend verschickt * werden soll */ protected boolean isInteresting( Element element ){ return true; }
die kommentare von get und setElement sind irgendwie unnötig, sollte selbstsprechend sein. und eigentlich kannst du element ja public machen, es wird doch eh nichts überprüft.
bei isInteresting fehlt wohl noch ein "// todo!!!" oder?