Was ist für euch guter Programmcode?
-
ness: Schreib deine Kommentare im Template nicht einfach hintendran, sondern davor, weil du sonst zu weit in die Breite gehst. Dann würd ich noch ne menge Leerzeilen reinbauen (z.B. immer nach nem Kommentar mit ner Funktionsdeklaration). Dann noch ein paar Leerzeichen (hinter //, zwischen () und const).
Inhaltlich hab ichs mir noch nicht angeguckt.
-
Shade Of Mine schrieb:
Und was sagst du zu meiner anderen Kritik? Ich bin gerne bereit offen zu diskutieren.
So, dann werde ich eben Schlüsse aus der Kritik ziehen.
1.) Verwende keine defines, denn es ist nicht sinnvoll, das gesamte äußere Erscheinungsbild einer Anwendung einfach dadurch verändern zu können, dass man den symbolischen Konstanten andere Werte gibt. Besser ist es, an hundert verschiedenen Positionen irgendwo in hunderten Modulen die tatsächlichen Werte hinzuschreiben, denn wenn man dann dahinter kommt, dass die Textgroesse doch um 2 logische Einheiten größer sein soll, dann hat man das Vergnügen, dutzende Dateien durchsuchen zu müssen und den Wert eben hundertmal ausbessern zu dürfen, und das gleiche nochmal, wenn doch die kleiner Textgröße gereicht hätte. So schlägst du wenigstens Stunden an Zeit tot, was zwar mit define nicht nötig gewesen wäre (da hätte es gereicht den einen Wert daneben auszubessern), aber wie auch immer.
2.) Funktionen sollten ihrem Aufrufer generell keine Auskunft darüber geben, ob während ihrer Ausführung irgend welche Fehler aufgetreten sind, darum sollte man vor allem keine bool Werte zurückgeben, denn dann könnte man ja womöglich den Fehler bei Probeläufen sofort entdecken. Es macht einfach mehr Spaß, in einem großen Programm unter hunderten schweigenden Minifunktionen einen Fehler finden zu müssen.
3.) Verwende keine Zeiger auf Zeiger, denn ... warum eigentlich? Ach ja, das spart nämlich sehr viel Speicher und das ist <template Begruendung bitte> auch nicht gut.
4.) Als Elementfunktionen überladene arithmetische Operatoren sind nicht gut. Die sind nämlich zu wenig fehleranfällig, besser du überlädst sie global und lässt dich davon überraschen, was unter Mitwirkung Deiner Konvertierungskonstruktoren oft an interessanten Ergebnissen dabei heraus kommt. Ist einfach zu lustig (ach und explicit ist zwar alles andere Plattformunabhängig, aber wer braucht das schon bei Klassen für mathematische Objekte? Sind ja sowieso alle Plattformspezifisch).
------
Aus dem besagten Header wurde schliesslich ein Hauptprogramm, an dessen
Bezeichnern alleine man erkennt, was das Programm macht#include"MTdef.h" HINSTANCE instanz; MTactics DasSpiel; // Endlich - die gesamte Anwendung in ein Objekt gepackt LRESULT CALLBACK MessageHandler(HWND hwnd,UINT imsg, WPARAM wParam,LPARAM lParam){ switch(imsg){ case WM_CREATE: if(!DasSpiel.Create(instanz,hwnd)) MessageBox(NULL,"Fehler","Fehler",0); break; case WM_PAINT: DasSpiel.ShowAll(); break; case WM_COMMAND: DasSpiel.ProcessClick(wParam); if(DasSpiel.DoFast){ DasSpiel.DoFast=false; DasSpiel.ProcessClick(DasSpiel.reserve); } return 0; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd,imsg,wParam,lParam); } int WINAPI WinMain(HINSTANCE hinst,HINSTANCE phinst, LPSTR commline,int showstyle){ // usw usf. - das Übliche das hier steht
// Dieses Programm ist selbsterklärend, wie ich denke.
// Alles was passiert, ist, dass das Spiel erzeugt, mitunter neu gezeichnet
// wird, und schliesslich dass es Benutzer Eingaben beliebigen Typs zu ver-
// arbeiten imstande ist. Genau wie jedes andere Programm auch.--- Ein Projekt kann man frontal angehen, also einfach drauflosprogrammieren,
--- wenn einem der Code in einer Funktion zu lang wird, einen Funktionsnamen
--- dafür erfinden, weiterprogrammieren, wieder einen Funktionsnamen erfinden
--- und so weiter und so fort. Irgendwann hat man dann hunderte Funktionen,
--- wahrscheinlich auch eine Lösung für das Problem, und kann sogar von
--- Modularisierung sprechen.--- Oder man kann es aus simplen Bausteinen wie etwa Vektoren, Feldern,
--- Spielsteinen etc., die alle Elemente des Programmes sind, allmählich zu
--- einem Ganzen zusammenfügen. Und letzteres heisst dann objektorientiert.--- Gute Nacht
-
Bitte hör auf. Das ist ja schrecklich.
-
MecnelsNichtEingeloggt schrieb:
1.) Verwende keine defines, denn es ist nicht sinnvoll, das gesamte äußere Erscheinungsbild einer Anwendung einfach dadurch verändern zu können, dass man den symbolischen Konstanten andere Werte gibt. Besser ist es, an hundert verschiedenen Positionen irgendwo in hunderten Modulen die tatsächlichen Werte hinzuschreiben
Verarscht du mich?
2.) Funktionen sollten ihrem Aufrufer generell keine Auskunft darüber geben, ob während ihrer Ausführung irgend welche Fehler aufgetreten sind, darum sollte man vor allem keine bool Werte zurückgeben,
Weil es Exception gibt?
3.) Verwende keine Zeiger auf Zeiger, denn ... warum eigentlich? Ach ja, das spart nämlich sehr viel Speicher und das ist <template Begruendung bitte> auch nicht gut.
Man würde natürlich nie irgendetwas wrappen, damit es leichter verwendbar ist, oder?
4.) Als Elementfunktionen überladene arithmetische Operatoren sind nicht gut. Die sind nämlich zu wenig fehleranfällig, besser du überlädst sie global und lässt dich davon überraschen, was unter Mitwirkung Deiner Konvertierungskonstruktoren oft an interessanten Ergebnissen dabei heraus kommt.
Lies bei zeiten mal ein C++ Buch. Wie etwa Effective C++ oder ähnliches.
(ach und explicit ist zwar alles andere Plattformunabhängig, aber wer braucht das schon bei Klassen für mathematische Objekte? Sind ja sowieso alle Plattformspezifisch).
Ok, du verarscht mich.
Falls du der echte bist (bitte demnächst durch einloggen bestätigen/widerlegen) beende ich die Diskussion mit dir. Denn verarschen lasse ich mich nicht.--- Ein Projekt kann man frontal angehen, also einfach drauflosprogrammieren,
--- wenn einem der Code in einer Funktion zu lang wird, einen Funktionsnamen
--- dafür erfinden, weiterprogrammieren, wieder einen Funktionsnamen erfinden
--- und so weiter und so fort. Irgendwann hat man dann hunderte Funktionen,
--- wahrscheinlich auch eine Lösung für das Problem, und kann sogar von
--- Modularisierung sprechen.--- Oder man kann es aus simplen Bausteinen wie etwa Vektoren, Feldern,
--- Spielsteinen etc., die alle Elemente des Programmes sind, allmählich zu
--- einem Ganzen zusammenfügen. Und letzteres heisst dann objektorientiert.*lol* muss ich das echt kommentieren?
Ich kann bei mir in der Arbeit jeden fragen den ich will, die Antwort wird sein: kleine Funktionen, kleine Module mit kleinen öffentlichen Schnittstellen sind wesentlich wartbarer als ein paar monster funktionen.
Hier in dem Forum sind auch so ziemlich alle meiner Meinung (es gab noch keine Gegenstimme)Denk bei zeiten mal darüber nach.
Natürlich heißt dass es alle so machen nicht, dass es richtig ist. Aber man sollte die Gründe überlegen warum so viele Leute soviel zeit dafür opfern kompakte Funktionen und Module zu entwickeln, wenn es doch einfacher und besser wäre ohne plan alles in eine Funktion zu stecken...
-
MecnelsNichtEingeloggt schrieb:
1.) Verwende keine defines, denn es ist nicht sinnvoll, das gesamte äußere Erscheinungsbild einer Anwendung einfach dadurch verändern zu können, dass man den symbolischen Konstanten andere Werte gibt. Besser ist es, an hundert verschiedenen Positionen irgendwo in hunderten Modulen die tatsächlichen Werte hinzuschreiben, denn wenn man dann dahinter kommt, dass die Textgroesse doch um 2 logische Einheiten größer sein soll, dann hat man das Vergnügen, dutzende Dateien durchsuchen zu müssen und den Wert eben hundertmal ausbessern zu dürfen, und das gleiche nochmal, wenn doch die kleiner Textgröße gereicht hätte. So schlägst du wenigstens Stunden an Zeit tot, was zwar mit define nicht nötig gewesen wäre (da hätte es gereicht den einen Wert daneben auszubessern), aber
das hat keiner gesagt, du sollst "const int GROESSE = 100;" schreiben statt "#DEFINE GROESSE 100". den vorteil solltest du als erfahrener hase doch sofort erkennen.
MecnelsNichtEingeloggt schrieb:
2.) Funktionen sollten ihrem Aufrufer generell keine Auskunft darüber geben, ob während ihrer Ausführung irgend welche Fehler aufgetreten sind, darum sollte man vor allem keine bool Werte zurückgeben, denn dann könnte man ja womöglich den Fehler bei Probeläufen sofort entdecken. Es macht einfach mehr Spaß, in einem großen Programm unter hunderten schweigenden Minifunktionen einen Fehler finden zu müssen.
das hat keiner gesagt, du sollst exceptions verwenden. die sind dafür gemacht.
MecnelsNichtEingeloggt schrieb:
3.) Verwende keine Zeiger auf Zeiger, denn ... warum eigentlich? Ach ja, das spart nämlich sehr viel Speicher und das ist <template Begruendung bitte> auch nicht gut.
das hat keiner gesagt, du sollst std::vector o.ä. container verwenden um schwer auffindbare fehler zu vermeiden.
MecnelsNichtEingeloggt schrieb:
4.) Als Elementfunktionen überladene arithmetische Operatoren sind nicht gut. Die sind nämlich zu wenig fehleranfällig, besser du überlädst sie global und lässt dich davon überraschen, was unter Mitwirkung Deiner Konvertierungskonstruktoren oft an interessanten Ergebnissen dabei heraus kommt. Ist einfach zu lustig (ach und explicit ist zwar alles andere Plattformunabhängig, aber wer braucht das schon bei Klassen für mathematische Objekte? Sind ja sowieso alle Plattformspezifisch).
hä? "ich weiß irgendwas nicht genau, evtl. hatte ich unrecht, also behaupte ich einfach irgendwas" oder wie?
-
Shade Of Mine schrieb:
MecnelsNichtEingeloggt schrieb:
1.) Verwende keine defines, denn es ist nicht sinnvoll, das gesamte äußere Erscheinungsbild einer Anwendung einfach dadurch verändern zu können, dass man den symbolischen Konstanten andere Werte gibt. Besser ist es, an hundert verschiedenen Positionen irgendwo in hunderten Modulen die tatsächlichen Werte hinzuschreiben
Verarscht du mich?
2.) Funktionen sollten ihrem Aufrufer generell keine Auskunft darüber geben, ob während ihrer Ausführung irgend welche Fehler aufgetreten sind, darum sollte man vor allem keine bool Werte zurückgeben,
Weil es Exception gibt?
3.) Verwende keine Zeiger auf Zeiger, denn ... warum eigentlich? Ach ja, das spart nämlich sehr viel Speicher und das ist <template Begruendung bitte> auch nicht gut.
Man würde natürlich nie irgendetwas wrappen, damit es leichter verwendbar ist, oder?
4.) Als Elementfunktionen überladene arithmetische Operatoren sind nicht gut. Die sind nämlich zu wenig fehleranfällig, besser du überlädst sie global und lässt dich davon überraschen, was unter Mitwirkung Deiner Konvertierungskonstruktoren oft an interessanten Ergebnissen dabei heraus kommt.
Lies bei zeiten mal ein C++ Buch. Wie etwa Effective C++ oder ähnliches.
(ach und explicit ist zwar alles andere Plattformunabhängig, aber wer braucht das schon bei Klassen für mathematische Objekte? Sind ja sowieso alle Plattformspezifisch).
Ok, du verarscht mich.
Falls du der echte bist (bitte demnächst durch einloggen bestätigen/widerlegen) beende ich die Diskussion mit dir. Denn verarschen lasse ich mich nicht.--- Ein Projekt kann man frontal angehen, also einfach drauflosprogrammieren,
--- wenn einem der Code in einer Funktion zu lang wird, einen Funktionsnamen
--- dafür erfinden, weiterprogrammieren, wieder einen Funktionsnamen erfinden
--- und so weiter und so fort. Irgendwann hat man dann hunderte Funktionen,
--- wahrscheinlich auch eine Lösung für das Problem, und kann sogar von
--- Modularisierung sprechen.--- Oder man kann es aus simplen Bausteinen wie etwa Vektoren, Feldern,
--- Spielsteinen etc., die alle Elemente des Programmes sind, allmählich zu
--- einem Ganzen zusammenfügen. Und letzteres heisst dann objektorientiert.*lol* muss ich das echt kommentieren?
Ich kann bei mir in der Arbeit jeden fragen den ich will, die Antwort wird sein: kleine Funktionen, kleine Module mit kleinen öffentlichen Schnittstellen sind wesentlich wartbarer als ein paar monster funktionen.
Hier in dem Forum sind auch so ziemlich alle meiner Meinung (es gab noch keine Gegenstimme)Denk bei zeiten mal darüber nach.
Natürlich heißt dass es alle so machen nicht, dass es richtig ist. Aber man sollte die Gründe überlegen warum so viele Leute soviel zeit dafür opfern kompakte Funktionen und Module zu entwickeln, wenn es doch einfacher und besser wäre ohne plan alles in eine Funktion zu stecken...
#defines haben ihre Vorteile und ihre Nachteile.
Konstanten haben ihre Vorteile und ihre Nachteile.
Was man nimmt ist Geschmackssache, mir sind #defines lieber,
Dir vielleicht Konstanten, aber wie gesagt, egal.
Ich hab den Zynismus vielleicht ein bisschen zu weit getrieben, sorry.Wie man Operatoren überlädt ist ebenfalls von der Aufgabe abhängig,
die man damit lösen soll. Wenn Vektoren im Spiel sind, ist es meiner
Meinung besser, Elementfunktionen zu nehmen, Du bevorzugst globale
Operatoren und baust lieber explicit Constructors ein. Schon wieder:
Nur Geschmackssache. Viele Wege führen nach Rom, nur mein Ansatz ist
wahrscheinlich bequemer und weniger fehleranfällig. Aber wie gesagt -
nur meine Meinung.bool Rückgabe vs Exceptions: Exceptions sollten in krassen Ausnahmefällen zum Einsatz kommen (Ein Speichermedium existiert nicht und es wird versucht, darauf zu schreiben, um ein Beispiel zu nennen), aber wohl nicht, um Abkürzungen zu anderen Programmteilen zu nehmen. Das erinnert an Basic und Goto. Meine Meinung, darum schweigen meine Funktionen nicht darüber, ob sie eine Operation erfolgreich beenden konnten, sondern lassen es den Aufrufer mit true oder false wissen. Wieder: Geschmackssache. Rückgabewerte für Fehler ist die ältere Methode, aber sicher nicht schlechter (eher bewährter).
Zeiger auf Zeiger: Nicht jeder kommt mit der Zeigerarithmetik zu recht, dabei ist es doch so simpel. Wenn sie Dir aber zu kompliziert sind, dann kannst Du angesichts der heutzutage zur Verfügung stehenden Hauptspeichergrößen natürlich auch jedes Objekt extra im Speicher anlegen. Dieser Umgang mit dem Hauptspeicher wäre vor 20 Jahren katastrophal gewesen, und auch heute gibt es Anwendungen, in denen das nicht egal ist (aber die haben wahrscheinlich etwas mit der NASA oder ähnlichen abstrusen Vereinen zu tun).
Sollte ich Dir mit meiner letzten Post zu sehr auf den Schlips getreten sein, so musst Du schon zugeben, dass das angesichts Deiner Kommentare zu meinen Posts nicht von ungefähr gekommen ist. Trotzdem - war nicht böse gemeint.
Viele kleine Bausteine verknüpft mit Logik ergeben ein geordnetes Ganzes.
--- ein bekannter Kybernetiker der 60er Jahre_Vordenker der ObjektorientierungGute Nacht.
-
Kann es sein das dieser Mecnels ein Troll ist und alle ihn abfüttern?
-
Vielleicht wäre es aber mal an der Zeit sich von seinen "bewährten" Verfahren zu lösen und Neuland zu betreten?
Kannst Du mal kurz erklären, warum Deine überladenen Operatoren Members sein sollen? Dann hast Du die implizite Konvertierung sofern nicht durch explicit unterdrück ja immer noch, halt auf dem rechten Argument. Das heißt a+b funktioniert dann, aber b+a nicht... das klingt irgendwie nicht so wirklich sinnvoll, oder?
Und wenn Du das verhinderst indem Du den Konstruktor explicit machst... dann sehe ich nicht was es bringen soll, das als Member zu machen.
-
#defines haben ihre Vorteile und ihre Nachteile.
Konstanten haben ihre Vorteile und ihre Nachteile.
Was man nimmt ist Geschmackssache, mir sind #defines lieber,
Dir vielleicht Konstanten, aber wie gesagt, egal.
Ich hab den Zynismus vielleicht ein bisschen zu weit getrieben, sorry.Du hast wirklich noch kein C++ Buch gelesen. Meyers, Effective C++, Die erste Richtlinie überhaupt.
Das erinnert an Basic und Goto.
Das was du tust, erinnert daran
Rückgabewerte für Fehler ist die ältere Methode, aber sicher nicht schlechter (eher bewährter).
Starrsinn³
wäre vor 20 Jahren katastrophal gewesen
Ich denke dieser Satz ist bezeichnend für deinen ganzen tollen Programmierstil...
-
Mecnels schrieb:
#defines haben ihre Vorteile und ihre Nachteile.
Konstanten haben ihre Vorteile und ihre Nachteile.
Was man nimmt ist Geschmackssache, mir sind #defines lieber,
Dir vielleicht Konstanten, aber wie gesagt, egal.naja, welche vorteile haben denn symbolische konstanten gegenüber echten? daß man die typsicherheit umgeht oder was? sag mal, da bin ich echt gespannt, was ich alles verpaßt habe, seit ich kein #define mehr verwende...
Mecnels schrieb:
Viele kleine Bausteine verknüpft mit Logik ergeben ein geordnetes Ganzes.
ist absolut richtig. dein problem dabei ist, daß du unfähig bist, diese alte erkenntnis auf die programmierung mit c++ anzuwenden. denn jeder der vielen kleinen bausteine ist entweder klasse oder funktion. in dem moment, in dem du eine funktion lauter verschiedene sachen selbst erledigen läßt, hast du aber eben nicht viele kleine bausteine, sondern wenige klobige. siehst du das denn nicht selber?!?
-
Jester schrieb:
Vielleicht wäre es aber mal an der Zeit sich von seinen "bewährten" Verfahren zu lösen und Neuland zu betreten?
Kannst Du mal kurz erklären, warum Deine überladenen Operatoren Members sein sollen? Dann hast Du die implizite Konvertierung sofern nicht durch explicit unterdrück ja immer noch, halt auf dem rechten Argument. Das heißt a+b funktioniert dann, aber b+a nicht... das klingt irgendwie nicht so wirklich sinnvoll, oder?
Und wenn Du das verhinderst indem Du den Konstruktor explicit machst... dann sehe ich nicht was es bringen soll, das als Member zu machen.Der eigentliche Punkt ist dass ein Konvertierungskonstruktor Zahl->Vektor für einen Vektor schon unsinnig ist, ob jetzt explicit oder nicht spielt da keine Rolle. In Anbetracht dessen ist es VÖLLIG EGAL ob das + jetzt Elementfunktion oder global ist, und mir deshalb die Kritik an der Implementierung als Elementfunktion sehr suspekt (weil wieder einmal kritisiert wurde ohne zu überlegen). Zahl und Vektor haben soviel gemeinsam wie Auto und Regenwurm, und niemand konvertiert Autos in Regenwürmer.
-
Mecnels schrieb:
#defines haben ihre Vorteile und ihre Nachteile.
Konstanten haben ihre Vorteile und ihre Nachteile.Vorteile von #defines wären?
zB in effective C++ super nachlesbar warum #define hier nur nachteile hat (betonung auf _nur_)Wie man Operatoren überlädt ist ebenfalls von der Aufgabe abhängig,
die man damit lösen soll. Wenn Vektoren im Spiel sind, ist es meiner
Meinung besser, Elementfunktionen zu nehmen, Du bevorzugst globale
Operatoren und baust lieber explicit Constructors ein. Schon wieder:
Nur Geschmackssache. Viele Wege führen nach Rom, nur mein Ansatz ist
wahrscheinlich bequemer und weniger fehleranfällig. Aber wie gesagt -
nur meine Meinung.Klar, dein Ansatz ist besser
Dein Problem ist doch: wenn der Ctor nicht explicit ist, hast du nicht nur beim op+ diese Konvertierungsprobleme, sondern bei Funktionsaufrufen auch.Natürlich macht es in dieser Situation keinen großen Unterschied, aber es hat keinen Vorteil den op+ als member zu deklarieren, es bricht nur die konsistenz.
Oder willst du mir nochmal genau erklären warum der op+ member sein muss?
Wenn wir von
struct C { C(int) {} };
ausgehen. Dann könnte man bei einem op+ als member
1+C() nicht schreiben, wohl aber
C()+1
was doch etwas komisch ist, oder?
wäre der Ctor explicit, könnte man keins der beiden schreiben.
wenn wir nun aber den op+ als non member definieren, kann man
1+C() und C()+1 schreiben, sofern der Ctor nicht explicit ist und keins von beiden, wenn er es nicht ist.dein vektor kann nicht umwandeln, weil er keinen umwandlungskonstruktor hat.
Und nun ekläre mir den vorteil von einem op+ als member.
Umwandlung zählt nicht, weil ich das gerade widerlegt habe.Mein grund warum man ihn non member machen sollte: konsistenz
bool Rückgabe vs Exceptions: Exceptions sollten in krassen Ausnahmefällen zum Einsatz kommen
Nein, bei jeder Art von Ausnahme. Sonst würde sie ja fatalError und nicht Exception heißen.
darum schweigen meine Funktionen nicht darüber, ob sie eine Operation erfolgreich beenden konnten, sondern lassen es den Aufrufer mit true oder false wissen.
Exception schweigen auch nicht, und sind einer C mäßigen fehlerbehandlung technisch überlegen.
Soll ich die technischen Vorteile aufzählen?Andererseits hat dein bool ein Problem: der Call hat keine Ahnung was passiert ist. Das ist doch ein gravierendes Problem, oder etwa nicht?
Wenn wir jetzt davon ausgehen, dass eine Funktion "DisplayScene" welche die ganze Ausgabe auf den Bildschirm rendern sollte einfach false liefert - was macht der caller dann?
Es kann an soviel liegen, lost surface? kein speicher mehr? illegale parameter beim aufruf? sonst was?
er weiß es nicht.
Also wären zumindest integer recht praktisch, damit der caller irgendwie reagieren kann.Wie lautet deine Begründung warum der caller nicht auf fehler reagieren darf? Oder speicherst du dann den fehlercode errno mäßig in einer externen variablen?
Zeiger auf Zeiger: Nicht jeder kommt mit der Zeigerarithmetik zu recht, dabei ist es doch so simpel. Wenn sie Dir aber zu kompliziert sind, dann kannst Du angesichts der heutzutage zur Verfügung stehenden Hauptspeichergrößen natürlich auch jedes Objekt extra im Speicher anlegen.
Verarsch mich bitte nicht.
Ich rede nicht von vector<vector<int> > weil das klar arsch lahm ist.
Ich rede von einem wrappen um diese Zeiger, weil es einfach leichter zu verwenden ist.
Und komm mir nicht mit "ich versteh zeiger arithmetik nicht". Aber vergleiche mal den Aufwand beim Speichermanagement von einem Type** mit dem von einem Wrapper.
Man schreibt diesen Wrapper einmal und hat ihn immer - nie mehr speicherprobleme.
weiters wird der code ausgelagert, es ist doch für deinen Code egal wie du zu dem element [x][y] kommst, also pack es in eine externe Funktion.
Dann kann man die Repräsentation später noch ändern.In C++ gibt es das schöne: zero cost principle
So ein wrapper ist in C++ gratis. er kostet keine performance.Dieser Umgang mit dem Hauptspeicher wäre vor 20 Jahren katastrophal gewesen,
Ich glaube du willst nicht lesen was ich schreibe, oder es versuchen zu verstehen.
Niemand sagt, du sollst ineffizient programmieren. Aber Zeiger auf Zeiger kann man auch anders lösen (ohne dauernd neue Objekt zu erstellen) weil es die Erfindung von Wrappern gibt.
Zeiger sind doch keine Magie. Sie zeigen einfach auf ein Objekt. Diese Objekte brauchen Platz. Logisch. Nur wenn ich die Zeiger schön wrappe, wo sollte da der Speicherverbrauch aufeinmal explodieren?
Klar, wenn man dann einfach immer kopien macht, statt die Objekte nur zu referenzieren hat man probleme - aber wer wäre so dumm so etwas zu tun?
Viele kleine Bausteine verknüpft mit Logik ergeben ein geordnetes Ganzes.
--- ein bekannter Kybernetiker der 60er Jahre_Vordenker der ObjektorientierungEben, genau das behaupte ich ja auch.
Viele kleine Bausteine.
Nicht ein großer, fetter Baustein.Natürlich sind meine Kommentare auch überspitzt, aber ich gehe auf deine Argumente ein. Und drehe dir deine Worte nicht im Mund um (wie du zB bei #define <-> const)
-
besserwisser schrieb:
naja, welche vorteile haben denn symbolische konstanten gegenüber echten? daß man die typsicherheit umgeht oder was? sag mal, da bin ich echt gespannt, was ich alles verpaßt habe, seit ich kein #define mehr verwende...
Konstanten dürfen WIRKLICH nur ein einziges Mal definiert werden, und sind deshalb nicht dafür geeignet, in einem Header zu stehen.
Bei define ist das egal, weil da immer die letzte Definition gilt, die sich natürlich beim selben Header niemals von eventuell vorhergehenden Definitionen unterscheidet.Stell Dir vor, du benötigst den selben Header in den unterschiedlichsten Modulen, dann kannst Du Dir mit Konstanten, die im Header stehen, vom Compiler üblicherweise anhören, dass doppelte Definitionen von Konstanten nicht erlaubt sind, was Konstanten völlig ungeeignet macht, mehreren Modulen zur Verfügung zu stehen. Du musst dann anfangen mit extern und static umständlich Gültigkeitsbereiche zu erfinden, damit das trotzdem geht. Dabei geht es viel einfacher mit #define, da sparst Du dir damit eine Menge Ärger.
Nur ein gut gemeinter Rat.
-
Mecnels schrieb:
Nur ein gut gemeinter Rat.
Der dummerweise völliger Käse ist.
Konstanten dürfen WIRKLICH nur ein einziges Mal definiert werden, und sind deshalb nicht dafür geeignet, in einem Header zu stehen.
Käse. Konstanten können ganz wunderbar in Headern stehen. const heißt in C++ automatisch static, also internal linkage. Desweiteren sind Integerkonstanten in C++ Compile-Zeit-Konstanten, d.h. es wird, sofern du nicht die Adresse der Konstanten bildest, kein Speicher benötigt.
Stell Dir vor, du benötigst den selben Header in den unterschiedlichsten Modulen, dann kannst Du Dir mit Konstanten, die im Header stehen, vom Compiler üblicherweise anhören, dass doppelte Definitionen von Konstanten nicht erlaubt sind, was Konstanten völlig ungeeignet macht, mehreren Modulen zur Verfügung zu stehen
Käse. Wahrscheinlich hast du irgendwann mal geschrieben:
const char* bla = "Fred";
und dann hat sich dein Linker beschwert (zurecht) und du hast die völlig falschen Schlüsse gezogen.
-
HumeSikkins schrieb:
Mecnels schrieb:
Nur ein gut gemeinter Rat.
Der dummerweise völliger Käse ist.
was sogar ich als neuling weiß, weil ichs in meinen paar miniprogrammen, die ich bis jetzt nur erstellt hab, verwendet habe. Mecnels, du hast einfach keine praktische erfahrungen mit sowas. nichts gegen das gedankenexperiment an sich, aber ab und an sollte man seine theorien in der praxis erproben.
ich meine, ich bin durchaus kein anhänger von gruppenzwang, aber wenigstens könntest du doch inzwischen (nachdem sich immer noch niemand FÜR deinen programmierstil ausgesprochen hat) mal auf die idee gekommen sein "hey, ich probier einfach mal aus, was die da die ganze zeit beschreiben". was würdest du schon verlieren? entweder hast du recht, dann kannst du viel aufrichtiger deine meinung weiterhin vertreten, oder wir haben recht, dann kannst du dich verbessern. und ist es nicht dein ziel, dich weiterzuentwickeln, dich und das, was du erschaffst, immer weiter zu verbessern?
-
Mecnels schrieb:
Zahl und Vektor haben soviel gemeinsam wie Auto und Regenwurm, und niemand konvertiert Autos in Regenwürmer.
Das will auch niemand machen...
Aber was stört dich zB an explicit für den Ctor?Wenn dein Vektor einen Ctor mit nur einem int als Param nehmen würde, dann würde dein Grund gegen op+ als non member zutreffen.
Natürlich würde man dann den Ctor explicit deklarieren und eine Konvertierung findet nicht statt.
Interessanterweise hast du ohne explicit aber enorme Probleme:
void f(Vektor); f(1);
würde plötzlich gehen.
schlimm schlimm
Deshalb ist explicit keine spielerei die unnötig ist, sondern essentiell.
Natürlich ist op+ als member kein fehler, solange du nur vektors miteinander addierst.
aber wenn du einen neuen op+ dazu gibst, dann hast du einen op+ als member und einen als non member. das stört doch die konsistenz, oder?
ich mag es, wenn sachen die zusammen gehören an einer stelle sind.
-
besserwisser schrieb:
was sogar ich als neuling weiß, weil ichs in meinen paar miniprogrammen, die ich bis jetzt nur erstellt hab, verwendet habe. Mecnels, du hast einfach keine praktische erfahrungen mit sowas. nichts gegen das gedankenexperiment an sich, aber ab und an sollte man seine theorien in der praxis erproben.
Du hast ganz recht, von ein paar miniprogrogrammen sollte man wirklich nicht auf die Praxis schließen.
In der Praxis interessiert es die Verwender Deiner Funktionen überhaupt nicht, wie Du irgend etwas implementiert hast, die erwarten nämlich nur, dass die Schnittstelle eine Schnittstelle ist, sprich, das macht, was draufsteht, wenn sie sie verwenden wollen. (Genau dazu kapselt man nämlich die internen Daten - um den tatsächlichen Umfang der Klasse zu verstecken und dem Anwender zu ersparen, sich Gedanken darüber zu machen, warum die Schnittstelle funktioniert)
Irgendwie seid ihr komische Käuze, die einen verteufeln es, Microsoft Code als Vorbild zu nehmen, ist ja klar, er wird ja auch nur von den bestbezahlten Spitzenprogrammierern der Welt entwickelt (aber ihr wisst es ja sicher besser).
Die anderen wie unwissender und Shade schreiben ein paar Miniprogramme wie TicTacToe und wollen einem einreden, dass man seit 20 Jahren und nach einigen hundert Projekten praxisfern arbeitet.
Bedenklich ist nur, dass Euch Eure eigenen Widersprüche gar nicht auffallen, weil Ihr Euch so auf mich eingeschossen habt.
Nehm's Euch trotzdem nicht übel, empfehle unwissender einfach einmal, C++ Das Grundlagen Buch (auch wenn's viel Arbeit ist, 1000 Seiten durch zu ackern), das ist nämlich wirklich eines der besseren Bücher, die im Laufe der letzten Jahre erschienen sind. Und wenn dann die Grundlagen einmal sitzen, dann seht Ihr vielleicht einige meiner Diskussionsbeiträge in einem anderen Licht, fürchtet Euch nicht mehr, Zeiger einzusetzen, wo sie nötig sind usw.
Bis dann.
-
Du Hirn. Wir fürchten uns nicht, Zeiger einzusetzen. Es geht darum, Zeiger zu wrappen, damit man weniger Dinge vergessen kann. Wenn ich nen auto_ptr hab, kann ich das deleten nicht vergessen, auch nicht bei Exceptions. Wenn ich nen vector nehme, kann ich das deleten nicht vergessen und ne Indexprüfung einbauen.
Du krasser Ober-Hacker vergisst sowas natürlich sowieso nicht. Das passiert nur uns. Die anderen haben wirklich gute Gründe vorgetragen für bestimmte Dinge und nicht nur ich habe dir eine ganz konkrete Buchempfehlung ausgesprochen.
Dein Alterstarrsin kann einen ganz schön auf den Keks gehen. Seit wann arbeiten bei Microsoft Spitzenprogrammierer? Natürlich wird es dort auch gute geben, genauso wie es dort auch schlechte geben wird und falls du es noch nicht gemerkt hast:
DAS WINDOWS API IST C OHNE ++ !!Und was du codest ist auch C ohne ++ vielleicht noch mit Klassen. Zum letzten mal: Lies Scott Meiers. Und lerne C++ damit. Du bist nicht im Recht, nur weil du dich als alten Hasen siehst. Und wenn du glaubst, das Shade noch nichts anderes als ein TicTAcToe zustande gebracht ha, täuscht du dich. Das war ein Design-Experiment, etwas was dir anscheinend überhaupt nichts sagt.
</Diskussion>
-
MecnelsAmArbeitsplatz schrieb:
In der Praxis interessiert es die Verwender Deiner Funktionen überhaupt nicht, wie Du irgend etwas implementiert hast, die erwarten nämlich nur, dass die Schnittstelle eine Schnittstelle ist, sprich, das macht, was draufsteht, wenn sie sie verwenden wollen.
Ich rede nicht von Client Code. Denn dann dürften wir uns nur die Schnittstelle ansehen, aber nicht die Implementierung. Und um eine Schnittstelle beurteilen zu können, braucht man viel wissen um die Domain.
Es geht hier um die Implementierung. Und da spielt wartbarer Code eine sehr große Rolle, oder schreibst du nur wegwerfcode? Vermutlich nicht, deshalb ist es wichtig, dass er wartbar bleibt. Und da ist die Implementierung durchaus interessant (schließlich kann man an der Schnittstelle nicht viel warten ;))
Irgendwie seid ihr komische Käuze, die einen verteufeln es, Microsoft Code als Vorbild zu nehmen, ist ja klar, er wird ja auch nur von den bestbezahlten Spitzenprogrammierern der Welt entwickelt (aber ihr wisst es ja sicher besser).
WinAPI Code ist nicht schön. Kann dir jeder hier bestätigen.
Natürlich ist er funktionell und es ist eine wahnsinns Leistung von MS die Winapi so stabil zu halten. Aber sie ist auch eine C API, deshalb sind einige Designentscheidungen in C++ nicht vertretbar. Denn C++ und C sind halt doch 2 verschiedene Sprachen.Die anderen wie unwissender und Shade schreiben ein paar Miniprogramme wie TicTacToe und wollen einem einreden, dass man seit 20 Jahren und nach einigen hundert Projekten praxisfern arbeitet.
Wie kommst du darauf?
Ich habe sicher nicht mehr Erfahrung als du, aber ich bin auch schon ein paar Jahre "in the real world". Habe als doch ein wenig einblick.Bedenklich ist nur, dass Euch Eure eigenen Widersprüche gar nicht auffallen, weil Ihr Euch so auf mich eingeschossen habt.
Oh, sehr schön. Welche denn? Ich will ja lernen...
Aber du bringst leider kaum Argumente
Wie soll ich dann je besser werden? Ich lege meine Argumente offen da, du kannst nachfragen (und wenn es dir gelingt, mich in widersprüche verstricken) usw. aber du zeigst leider kaum argumentedas macht die sache recht schwer darüber zu diskutieren.
zB welche vorteile haben #defines gegenüber konstanten?
warum sind wrapper böse?
was spricht gegen explicit bei einem ctor der nicht zur konvertierungen verwendet werden soll?
usw.Und wenn dann die Grundlagen einmal sitzen, dann seht Ihr vielleicht einige meiner Diskussionsbeiträge in einem anderen Licht, fürchtet Euch nicht mehr, Zeiger einzusetzen, wo sie nötig sind usw.
Bitte erklär deinen Standpunkt doch.
Und lies bitte was ich schreibe. Ich habe nicht gesagt: verwende keine Zeiger, sondern ich habe gesagt: wrappe sie lieber.Ich würde von mir nie behaupten C++ zu beherrschen (außer einem Personalchef gegenüber ;)) aber die Grundlagen kann ich mittlerweile schon ganz gut. Und Zeiger stellen für mich auch kein Problem da. Aber dennoch finde ich es schöner, mich nicht darum kümmern zu müssen, weil es ein Wrapper macht.
Das spart mir Zeit und reduziert die Fehlerquellen und das bedeutet weniger Zeit geht für das Debuggen drauf. Und das macht mich glücklich
btw: ich habe den heutigen Vormittag damit verbracht den Code für die Anwendung die ich gerade schreibe zu kürzen und ein neues Modul eingeführt
Das erlaubt leichtere erweiterung des Codes, weil man nun nur ein kleines Modul ändern muss um neue Funktionalität hinzufügen zu können, statt wie vorher direkt im Source code an 2 stellen die änderungen vorzunehmen.
-
MecnelsAmArbeitsplatz schrieb:
Irgendwie seid ihr komische Käuze, die einen verteufeln es, Microsoft Code als Vorbild zu nehmen, ist ja klar, er wird ja auch nur von den bestbezahlten Spitzenprogrammierern der Welt entwickelt (aber ihr wisst es ja sicher besser).
Tut mir leid, aber looooooooooooooooooooooool
Guck Dir den Code an, dann weißt Du wie man NICHT programieren sollte. Wenn die so toll wären, hätten sie dann so übermäßig viele Sicherheitslücken?
Wenn Du guten Code sehen willst, dann guck Dir z. B. Linux, POSIX, Boost und co. an.
Jetzt muss ich mich weiter tot lachen