Methoden mit bool-Parametern und "Lesbarkeit" im Kontext
-
Xin schrieb:
Hallo CStoll,
könntest Du statt "quote" "quote=werauchimmer" schreiben und bitte zwischen den Absätzen eine Leerzeile einfügen? Es ist ziemlich schwierig in einem Klumpen Text die Stelle zu suchen, wo man eine Antwort zwischenfügen möchte. Eine Leerzeile zwischen den Quotes hilft da ungemein. Ohne die Suchfunktion geht bei Deinen Antworten leider gar nix. Versuch bevor Du auf dieses Posting antwortest mal (ohne Abschicken) Dein Posting zu zitieren und die Stellen zu finden, wo andere Leute antworten würden. Du wirst die Zwischenzeile danach bei mir zu schätzen wissen
OK, ich werde mich in Zukunft bemühen.
Xin schrieb:
CStoll schrieb:
Xin schrieb:
Jedes Flag ist eine unabhängige Frage. Ob die sich beeinflussen oder nicht, merkst Du an den Flags nicht.
Und genau das ist das Problem bei deinem Ansatz: Ich will den Flags ansehen, welche sich gegenseitig beeinflussen und welche nicht.
Das ist kein Problem meines Ansatzes. Ein Flag ist eine unabhängige Ja/Nein-Frage. Ob die sich gegenseitig beeinflussen entscheidet sich nicht am Ort, wo das Flag gespeichert wird, sondern im Algorithmus, der die Flags auswertet.
Ich will es aber an dem Ort wissen, wo ich die Flags verwende - dem Code
dlg = Dialog::Fullscreen; dlg = Dialog::Modal;
sieht man nicht an, ob der Dialog hinterher noch im Vollbild-Modus ist oder nicht (und selbst mit expliziten Angaben WindowFlag::Fullscreen bzw. DialogFlag::Modal mußt du erstmal nachsehen, welchen Typ beides hat - ein Anwender könnte durchaus auf die Idee kommen, die DialogFlag-Klasse nur als Sammlung von zusätzlichen WindowFlag-Werten anzulegen).
Xin schrieb:
CStoll schrieb:
CStoll schrieb:
Ich kombiniere Flags schon über & und |
Dann sind die Operatoren doch semantisch sinnvoll gewählt.
Auch auf die Gefahr hin, mich zu wiederholen: An den Operatoren habe ich nichts auszusetzen - nur an der Vererbungsbeziehung (aber du kannst es dir gerne leicht machen, und meine Sätze nur bis zur Hälfte lesen :D).
Ich habe Deine Kritik durchaus gelesen, zur Kenntnis genommen und das Thema ist subjektiver Natur. Also was soll ich dazu noch schreiben? Es gibt gute Gründe für Vererbung, wie es gute Gründe gegen Vererbung gibt.
Du kritisiertest auch die Wahl der Operatoren, weil die ja keiner verstehen würde und wolltest HasFlags() usw. haben. Das kommentierte ich - dafür brauche ich den Rest nicht zu quoten.Genauer: Ich kritisiere das Zusammenwirken von Vererbung und Operatoren - die Operatoren alleine sind brauchbar (mit den Flags als Member), die Vererbungsbeziehung alleine auch (allerdings nicht von Flags, sondern von Flaggable aus), beides zusammen erzeugt unleserlichen - und darum gefährlichen - Code.
Xin schrieb:
CStoll schrieb:
CStoll schrieb:
Nein, Flags sind nicht flagbar, bestenfalls kombinierbar.
Die Klasse Flags ist flagbar. Genau das ist ihre Funktion.
Kannst du in einem Flag andere Flags setzen? Nein. Ein Flag ist eine Marke, die aussagt, ob etwas eine bestimmte Eigenschaft hat. Dieses etwas ist vielleicht flagbar, aber nicht das flag selber.
Die Klasse heißt Flags, nicht Flag. Sie repräsentiert Flags, nicht ein Flag. Und sie ist flaggbar, denn genau das ist ihre Aufgabe.
Wenn du das aus dieser Sicht siehst, dann sollten die konkreten Flag-Werte aber keine Objekte der Klasse "Flags" sein - diese präsentieren nämlich ein einzelnes Flag.
Xin schrieb:
CStoll schrieb:
Wenn ich einen Rückzieher mache, dann mache ich das deutlicher, das sieht dann ungefähr so aus:
Was den operator bool() angeht, habe ich mich zu weit aus dem Fenster gelehnt, weil ich hier was durcheinander geworfen habe und es jetzt auch schon wieder einige Zeit her ist, seitdem ich die Flagklassen entworfen habe.
Ergo gilt auch das Argument von Shade, bzgl. if( win ). Ein offizielles und ernstgemeines Sorry an ihn und einen nicht ganz so ernstgemeinten Kniefall.Da siehst du es - noch nicht einmal du selber weißt, was man mit deinen Flag-Klassen machen kann. Wie soll da noch ein anderer Programmierer, der nur deinen Code sieht, da durchblicken?
*lach*, ich habe die Klasse jetzt seit locker einem Jahr nicht mehr angeguckt. Sie funktioniert einwandtfrei. Das Problem ist nicht, dass ich da nicht durchblicke, sondern dass ich derzeit in zwei ähnlichen Sprachwelten hänge.
Du verstehst (zumindest rudimentär) beide Sprachwelten - andere Entwickler kennen nur eine Seite. Und da erwartest du, daß sie die Beweggründe hinter deinem Design ohne Hilfen durchschauen?
Xin schrieb:
Auch meine Klassen sind mit Doxygen dokumentiert. Aber nicht, weil sie nicht intuitiv wären, sondern weil es soviele sind, dass ich nicht immer alles im Kopf halten kann. Muss man irgendwo etwas ändern, wo man ein paar Jahre nicht mehr vorbeigeschaut hat, so ist die Dokumentation hilfreich.
Daß sie dokumentiert sind, glaube ich dir, aber hast du die ganzen Fallstricke, die du auf den letzten Seiten erfolgreich ignoriert hast (ala "verwende niemals 'if(win)'" oder die möglichen Abhängigkeiten verschiedener Flags) dort ausführlich beschrieben? Wenn nein, wird ziemlich schnell jemand auf die Idee kommen, die "verbotenen" Möglichkeiten auszunutzen.
CStoll schrieb:
Zwei operator &-Funktionen stehen zur Auswahl. Eine Signatur passt perfekt, die andere passt überhaupt nicht.
Und der Aufruf soll mehrdeutig sein.Nicht ganz - die Funktion Window hat keinen einzigen operator& - aber es gibt zwei (auf verschiedenen Wegen) geerbte Funktionen, die passen könnten.
Das kann nicht die Erklärung sein, denn das würde die Verwendung von vererbten Funktionen jeglicher Art verhindern. Es gibt zwei (auf verschiedenen Wegen) geerbte Funktionen, von denen aber eine überhaupt nicht passt und eine genau passt.
Keine der Funktionen passt genau - bei beiden müsste der erste Operand umgewandelt werden in eine Basisklasse.
Achja, wo wir gerade beim Thema sind - ich hab' tatsächlich etwas passendes gefunden:
ARM schrieb:
Access to base class members must be unambigous. Access to a base class member is ambiguos if the expession used refers to more than one function, object, type, or enumerator. The check for ambiguity takes place before access control (§11). For example,
class A { public: int a; int (*b)(); int f(); int f(int); int g(); }; class B { int a; int b(); public: int f(); int g; int h(); int h(int); }; class C : public A, public B {}; void g(C* pc) { pc->a = 1; // error: ambigous: A::a or B::a pc->b(); // error: ambigous: A::b or B::b pc->f(); // error: ambigous: A::f or B::f pc->f(1); // error: ambigous: A::f or B::f pc->g(); // error: ambigous: A::g or B::g pc->g = 1; // error: ambigous: A::g or B::g pc->h(); // ok pc->h(1); // ok }
If the name of an overloaded function is unambiguously found overloading resolution also takes place before access control.
[...]
Checking for ambiguity is done before access control or type checking (§10.1.1). Thus, an ambiguity exists when base class members have the same name, even if only one is accessible from the derived class.
(das stammt aus dem ARM - Kapitel 10.1.1, falls du nachlesen möchtest)
Oder auf deutsch: Zuerst wird überprüft, ob es einen eindeutigen Weg gibt, den Namen zuzuordnen, erst danach wird kontrolliert, ob er passt (betrachte den vierten Aufruf dort oben - es gibt nur einen f(int), aber er ist trotzdem mehrdeutig).
PS: Ich hab' nochmal über die Typerweiterungen nachgedacht - und in C++ sind die wohl besser mit Konvertierungsoperatoren darstellbar:
class WinFlag {...}; class Window { WinFlag f; public: operator WinFlag&() {return f;} ... };
-
CStoll schrieb:
Xin schrieb:
Du wirst die Zwischenzeile danach bei mir zu schätzen wissen
OK, ich werde mich in Zukunft bemühen.
Klappt doch super
CStoll schrieb:
Xin schrieb:
CStoll schrieb:
Xin schrieb:
Jedes Flag ist eine unabhängige Frage. Ob die sich beeinflussen oder nicht, merkst Du an den Flags nicht.
Und genau das ist das Problem bei deinem Ansatz: Ich will den Flags ansehen, welche sich gegenseitig beeinflussen und welche nicht.
Das ist kein Problem meines Ansatzes. Ein Flag ist eine unabhängige Ja/Nein-Frage. Ob die sich gegenseitig beeinflussen entscheidet sich nicht am Ort, wo das Flag gespeichert wird, sondern im Algorithmus, der die Flags auswertet.
Ich will es aber an dem Ort wissen, wo ich die Flags verwende - dem Code
dlg = Dialog::Fullscreen; dlg = Dialog::Modal;
sieht man nicht an, ob der Dialog hinterher noch im Vollbild-Modus ist oder nicht (und selbst mit expliziten Angaben WindowFlag::Fullscreen bzw. DialogFlag::Modal mußt du erstmal nachsehen, welchen Typ beides hat - ein Anwender könnte durchaus auf die Idee kommen, die DialogFlag-Klasse nur als Sammlung von zusätzlichen WindowFlag-Werten anzulegen).
Das hatten wir doch schon durchgekaut: Flags setzt man nicht mit =, sondern mit |=.
operator = wird protected, damit man die Defaultwerte setzen kann und diejenigen sicher sind, die damit nicht klarkommen.
Zumal die Problematik sowieso erledigt ist, weil der Compiler den Operator mehrdeutig findet.CStoll schrieb:
Genauer: Ich kritisiere das Zusammenwirken von Vererbung und Operatoren - die Operatoren alleine sind brauchbar (mit den Flags als Member), die Vererbungsbeziehung alleine auch (allerdings nicht von Flags, sondern von Flaggable aus), beides zusammen erzeugt unleserlichen - und darum gefährlichen - Code.
Dann nenn die Klasse Flagable.
Aber auch hier gilt, es spielt eigentlich keine Rolle mehr, da der Compiler die Geschichte nicht akzeptiert. Ich kann noch so tolle Ideen haben, solange sie in C++ nicht kompilierbar sind, taugen sie für C++ nichts.
Dass die Methode in C++ auch noch mehr Disziplin benötigt, als ich erwartete (genausoviel, als würde man ein Integer und Defines nehmen), macht die Sache nicht besser - von der Idee her aber auch nicht schlechter oder gefährlicher.
CStoll schrieb:
Xin schrieb:
Die Klasse heißt Flags, nicht Flag. Sie repräsentiert Flags, nicht ein Flag. Und sie ist flaggbar, denn genau das ist ihre Aufgabe.
Wenn du das aus dieser Sicht siehst, dann sollten die konkreten Flag-Werte aber keine Objekte der Klasse "Flags" sein - diese präsentieren nämlich ein einzelnes Flag.
...und ich dachte, ich wäre kleinlich.
Also in Zukunft class WindowFlag mit den einzelnen Flags, das wird dann protected auf WindowFlags abgeleitet, welches dann public auf Window abgeleitet wird. Ergebnis: WindowFlag(ohne s) enthält die einzelnen Flaggen, WindowFlags verwaltet viele Flaggen und Window weiß von nichts. (Nein, ich habe es nicht ausprobiert, das kam nur grade dabei rum, dass Du die Flags und das einzelne Flag auch noch trennen möchtest. Ob und wenn ja, was für Merkwürdigkeiten dabei rumkommen, juckt mich in dem Thread weniger, weil es ja nicht kompiliert.)CStoll schrieb:
Du verstehst (zumindest rudimentär) beide Sprachwelten - andere Entwickler kennen nur eine Seite. Und da erwartest du, daß sie die Beweggründe hinter deinem Design ohne Hilfen durchschauen?
Das Design ist leicht zu durchschauen, da braucht man nichtmals guten Willen dazu.
Wenn man natürlich operator & erst versteht, wenn man darauf aufmerksam gemacht wird, dass man das bei Integers genauso macht, dann frage ich mich, ob der ursprüngliche Wille nicht in die andere Richtung gingCStoll schrieb:
Daß sie dokumentiert sind, glaube ich dir, aber hast du die ganzen Fallstricke, die du auf den letzten Seiten erfolgreich ignoriert hast (ala "verwende niemals 'if(win)'" oder die möglichen Abhängigkeiten verschiedener Flags) dort ausführlich beschrieben? Wenn nein, wird ziemlich schnell jemand auf die Idee kommen, die "verbotenen" Möglichkeiten auszunutzen.
Wer if( win.Flags ) benutzt wird sowieso gesteinigt, sofern das nicht explizit erlaubt und begründet ist. Sobald da eine Flage hinzugefügt wird, die unabhängig von den Flaggen ist, die damit abgefragt werden wollen, geht das ganze schief. if( win.Flags & KombinationAusGewünschtenFlaggen ) ist wohl Pflicht, selbst wenn das alle existierenden Flaggen sind und der Rest nicht verwendet wird und grundsätzlich auf 0 steht.
CStoll schrieb:
Achja, wo wir gerade beim Thema sind - ich hab' tatsächlich etwas passendes gefunden:
ARM schrieb:
Access to base class members must be unambigous.
[...]Checking for ambiguity is done before access control or type checking (§10.1.1). Thus, an ambiguity exists when base class members have the same name, even if only one is accessible from the derived class.
(das stammt aus dem ARM - Kapitel 10.1.1, falls du nachlesen möchtest)
Würde ich gerne, insbesondere weil mich der Grund für diese Designentscheidung interessiert. Leider habe ich das ARM scheinbar nicht mehr, zumindest ist es verschwunden. :-\
Du hast nicht zufällig die Begründung zum Quoten da?
Alternativ nehme ich das ARM auch komplettCStoll schrieb:
PS: Ich hab' nochmal über die Typerweiterungen nachgedacht - und in C++ sind die wohl besser mit Konvertierungsoperatoren darstellbar:
class WinFlag {...}; class Window { WinFlag f; public: operator WinFlag&() {return f;} ... };
Dem stimme ich zu.
-
Xin, hast du schon mal darüber nachgedacht Politiker zu werden?
-
Xin schrieb:
CStoll schrieb:
Xin schrieb:
CStoll schrieb:
Xin schrieb:
Jedes Flag ist eine unabhängige Frage. Ob die sich beeinflussen oder nicht, merkst Du an den Flags nicht.
Und genau das ist das Problem bei deinem Ansatz: Ich will den Flags ansehen, welche sich gegenseitig beeinflussen und welche nicht.
Das ist kein Problem meines Ansatzes. Ein Flag ist eine unabhängige Ja/Nein-Frage. Ob die sich gegenseitig beeinflussen entscheidet sich nicht am Ort, wo das Flag gespeichert wird, sondern im Algorithmus, der die Flags auswertet.
Ich will es aber an dem Ort wissen, wo ich die Flags verwende - dem Code
dlg = Dialog::Fullscreen; dlg = Dialog::Modal;
sieht man nicht an, ob der Dialog hinterher noch im Vollbild-Modus ist oder nicht (und selbst mit expliziten Angaben WindowFlag::Fullscreen bzw. DialogFlag::Modal mußt du erstmal nachsehen, welchen Typ beides hat - ein Anwender könnte durchaus auf die Idee kommen, die DialogFlag-Klasse nur als Sammlung von zusätzlichen WindowFlag-Werten anzulegen).
Das hatten wir doch schon durchgekaut: Flags setzt man nicht mit =, sondern mit |=.
operator = wird protected, damit man die Defaultwerte setzen kann und diejenigen sicher sind, die damit nicht klarkommen.
Zumal die Problematik sowieso erledigt ist, weil der Compiler den Operator mehrdeutig findet.Und wozu gibt's dann die Zuweisung?
Xin schrieb:
CStoll schrieb:
Genauer: Ich kritisiere das Zusammenwirken von Vererbung und Operatoren - die Operatoren alleine sind brauchbar (mit den Flags als Member), die Vererbungsbeziehung alleine auch (allerdings nicht von Flags, sondern von Flaggable aus), beides zusammen erzeugt unleserlichen - und darum gefährlichen - Code.
Dann nenn die Klasse Flagable.
Mach ich ja, aber der Klasse Flagable würde ich keine Flag-Operatoren geben.
Xin schrieb:
CStoll schrieb:
Xin schrieb:
Die Klasse heißt Flags, nicht Flag. Sie repräsentiert Flags, nicht ein Flag. Und sie ist flaggbar, denn genau das ist ihre Aufgabe.
Wenn du das aus dieser Sicht siehst, dann sollten die konkreten Flag-Werte aber keine Objekte der Klasse "Flags" sein - diese präsentieren nämlich ein einzelnes Flag.
...und ich dachte, ich wäre kleinlich.
Also in Zukunft class WindowFlag mit den einzelnen Flags, das wird dann protected auf WindowFlags abgeleitet, welches dann public auf Window abgeleitet wird. Ergebnis: WindowFlag(ohne s) enthält die einzelnen Flaggen, WindowFlags verwaltet viele Flaggen und Window weiß von nichts. (Nein, ich habe es nicht ausprobiert, das kam nur grade dabei rum, dass Du die Flags und das einzelne Flag auch noch trennen möchtest. Ob und wenn ja, was für Merkwürdigkeiten dabei rumkommen, juckt mich in dem Thread weniger, weil es ja nicht kompiliert.)Wenn ich's trenne, dann in eine Klasse Flags (oder Flagable), von der Window abgeleitet wird und eine Klasse Flag - die von Flags genuzt wird (hier keine Ableitung). Und dann degeneriert Flag zu einem einfachen enum.
Xin schrieb:
CStoll schrieb:
Du verstehst (zumindest rudimentär) beide Sprachwelten - andere Entwickler kennen nur eine Seite. Und da erwartest du, daß sie die Beweggründe hinter deinem Design ohne Hilfen durchschauen?
Das Design ist leicht zu durchschauen, da braucht man nichtmals guten Willen dazu.
Wenn man natürlich operator & erst versteht, wenn man darauf aufmerksam gemacht wird, dass man das bei Integers genauso macht, dann frage ich mich, ob der ursprüngliche Wille nicht in die andere Richtung gingUnd als nächstes leitest du Window noch von Point ab, um es mit op+= über den Monitor schieben zu können? (oder bewirkt das eine Größenänderung des Fensters?) Ja, Integers kann man ver-und-en - aber Integers verwendet man auch nicht als Basis für eigene Klassen, um diese verunden zu können.
Xin schrieb:
CStoll schrieb:
Daß sie dokumentiert sind, glaube ich dir, aber hast du die ganzen Fallstricke, die du auf den letzten Seiten erfolgreich ignoriert hast (ala "verwende niemals 'if(win)'" oder die möglichen Abhängigkeiten verschiedener Flags) dort ausführlich beschrieben? Wenn nein, wird ziemlich schnell jemand auf die Idee kommen, die "verbotenen" Möglichkeiten auszunutzen.
Wer if( win.Flags ) benutzt wird sowieso gesteinigt, sofern das nicht explizit erlaubt und begründet ist. Sobald da eine Flage hinzugefügt wird, die unabhängig von den Flaggen ist, die damit abgefragt werden wollen, geht das ganze schief. if( win.Flags & KombinationAusGewünschtenFlaggen ) ist wohl Pflicht, selbst wenn das alle existierenden Flaggen sind und der Rest nicht verwendet wird und grundsätzlich auf 0 steht.
if(win.Flags) kann ich explizit verbieten, indem ich den Member privat mache (und nur HasFlag() etc anbiete), dein if(win) kann nur unter Aufwand verboten werden.
Xin schrieb:
CStoll schrieb:
Achja, wo wir gerade beim Thema sind - ich hab' tatsächlich etwas passendes gefunden:
ARM schrieb:
Access to base class members must be unambigous.
[...]Checking for ambiguity is done before access control or type checking (§10.1.1). Thus, an ambiguity exists when base class members have the same name, even if only one is accessible from the derived class.
(das stammt aus dem ARM - Kapitel 10.1.1, falls du nachlesen möchtest)
Würde ich gerne, insbesondere weil mich der Grund für diese Designentscheidung interessiert. Leider habe ich das ARM scheinbar nicht mehr, zumindest ist es verschwunden. :-\
Du hast nicht zufällig die Begründung zum Quoten da?
Alternativ nehme ich das ARM auch komplettIch hab' nochmal nachgesehen, aber eine echte Begründung dafür ist wohl gut versteckt.
-
CStoll schrieb:
Xin schrieb:
Das hatten wir doch schon durchgekaut: Flags setzt man nicht mit =, sondern mit |=.
operator = wird protected, damit man die Defaultwerte setzen kann und diejenigen sicher sind, die damit nicht klarkommen.
Zumal die Problematik sowieso erledigt ist, weil der Compiler den Operator mehrdeutig findet.Und wozu gibt's dann die Zuweisung?
Um Default-Werte zu setzen, zum Beispiel bei der Konstruktion.
Den Operator = braucht man eigentlich überhaupt nicht, höchstens um der zu flaggenden Klasse Dinge das Abschalten aller Flaggen und anschließendem Zusetzen der gewünschten Flaggen zu vereinfachen.
Flags in Verbindung mit operator = ist immer risikobehaftet.CStoll schrieb:
Xin schrieb:
CStoll schrieb:
Genauer: Ich kritisiere das Zusammenwirken von Vererbung und Operatoren - die Operatoren alleine sind brauchbar (mit den Flags als Member), die Vererbungsbeziehung alleine auch (allerdings nicht von Flags, sondern von Flaggable aus), beides zusammen erzeugt unleserlichen - und darum gefährlichen - Code.
Dann nenn die Klasse Flagable.
Mach ich ja, aber der Klasse Flagable würde ich keine Flag-Operatoren geben.
Warum nicht?
CStoll schrieb:
Xin schrieb:
CStoll schrieb:
Du verstehst (zumindest rudimentär) beide Sprachwelten - andere Entwickler kennen nur eine Seite. Und da erwartest du, daß sie die Beweggründe hinter deinem Design ohne Hilfen durchschauen?
Das Design ist leicht zu durchschauen, da braucht man nichtmals guten Willen dazu.
Wenn man natürlich operator & erst versteht, wenn man darauf aufmerksam gemacht wird, dass man das bei Integers genauso macht, dann frage ich mich, ob der ursprüngliche Wille nicht in die andere Richtung gingUnd als nächstes leitest du Window noch von Point ab, um es mit op+= über den Monitor schieben zu können? (oder bewirkt das eine Größenänderung des Fensters?)
Wieder habe ich das Gefühl, dass Du keinen guten Willen mitteilen möchtest. ^
Ich habe keine Fenster in meinem Framework, aber wenn Du mich so fragst, warum sollte ich Fenster nicht von einem Punkt ableiten? Genauer von einem Field, das ist eine positionierte(Point) Fläche (Area).
Um ein Fenster zu verschieben setze man entweder den Punkt oder verschiebe es um eine Distance.Vermutlich würde ich allerdings von Bitmap(abgeleitet von einer BitmapDescription, welche von Area abgeleitet wurde) ableiten und Punkt ableiten und einen operator & Field() erstellen.
Point ObenLinks, UntenRechts; class Window : public Point, public BitMap {} win = Position; // Wo? win = Area( UntenRechts - ObenLinks ); // Wie groß? win += Distance( 10, 10 ); // Ein wenig verschieben. win.DrawBox( Point::Zero, UntenRechts ); win.CopyFrom( CloseIcon, ObenLinks+Distance( 1, 1 ) ); win.DrawLine( Point( 1, CloseIcon.Height+1 ) ), Point(UntenRechts.x-1, CloseIcon.Height+1 ) ); win.DrawText( Point( CloseIcon.Width+1, 1 ), "Mein Fenster" ); printf( "Fenster befindet sich an Position %s, Fläche %s und ist hübsch bemalt.\n", Point( win ).ToString(), Area( win ).ToString() ); screen.CopyFrom( win, win );
Fertig ist das Fenster.
CStoll schrieb:
Ja, Integers kann man ver-und-en - aber Integers verwendet man auch nicht als Basis für eigene Klassen, um diese verunden zu können.
Warum eigentlich nicht?
Grade das ist doch die Kritik derer, die das "reine OOP" in C++ suchen.CStoll schrieb:
Xin schrieb:
CStoll schrieb:
Daß sie dokumentiert sind, glaube ich dir, aber hast du die ganzen Fallstricke, die du auf den letzten Seiten erfolgreich ignoriert hast (ala "verwende niemals 'if(win)'" oder die möglichen Abhängigkeiten verschiedener Flags) dort ausführlich beschrieben? Wenn nein, wird ziemlich schnell jemand auf die Idee kommen, die "verbotenen" Möglichkeiten auszunutzen.
Wer if( win.Flags ) benutzt wird sowieso gesteinigt, sofern das nicht explizit erlaubt und begründet ist. Sobald da eine Flage hinzugefügt wird, die unabhängig von den Flaggen ist, die damit abgefragt werden wollen, geht das ganze schief. if( win.Flags & KombinationAusGewünschtenFlaggen ) ist wohl Pflicht, selbst wenn das alle existierenden Flaggen sind und der Rest nicht verwendet wird und grundsätzlich auf 0 steht.
if(win.Flags) kann ich explizit verbieten, indem ich den Member privat mache (und nur HasFlag() etc anbiete), dein if(win) kann nur unter Aufwand verboten werden.
Du packst operator bool() als privates Member in Window?
CStoll schrieb:
Xin schrieb:
CStoll schrieb:
Achja, wo wir gerade beim Thema sind - ich hab' tatsächlich etwas passendes gefunden:
ARM schrieb:
Access to base class members must be unambigous.
[...]Checking for ambiguity is done before access control or type checking (§10.1.1). Thus, an ambiguity exists when base class members have the same name, even if only one is accessible from the derived class.
(das stammt aus dem ARM - Kapitel 10.1.1, falls du nachlesen möchtest)
Würde ich gerne, insbesondere weil mich der Grund für diese Designentscheidung interessiert. Leider habe ich das ARM scheinbar nicht mehr, zumindest ist es verschwunden. :-\
Du hast nicht zufällig die Begründung zum Quoten da?
Alternativ nehme ich das ARM auch komplettIch hab' nochmal nachgesehen, aber eine echte Begründung dafür ist wohl gut versteckt.
Das ist das Problem... ich brauche keine Regeln - ich brauche Begründungen, warum Regeln existieren. Viele Regeln existieren nämlich nur, weil man das schon immer so gemacht hat.
Das glaube ich in dem Fall nicht, aber es beantwortet nicht die Frage, warum selbst unmögliche Fälle als Möglichkeit erkannt werden, um dann zu argumentieren, dass es mehrdeutig sei.
Sicherlich ist hier eine Gefahr, wenn unwissentlich, mehrere Funktionen gleichen Namens und unterschiedlicher Signatur zusammen kommen, dass man die Basisklassenzugehörigkeit vertauschen könnte. Hier fehlt mir die Möglichkeit, die Zusammenführung aus der Basisklasse heraus explizit zu erlauben, ohne dafür neuen Code zu produzieren.
In meinem Fall ist die Zusammenführung ja gewünscht.Aber ich habe - was das angeht - auch eine unmoderne Sicht auf Programmiersprachen: Der Entwickler sollte alle Möglichkeiten haben, was natürlich dazu beiträgt, dass er auch die Verantwortung für die Möglichkeiten übernehmen muss. Das ist zur Zeit unpopulär. Nichtsdestrotrotz muss er von der Sprache soweit wie möglich unterstützt werden.
-
Xin schrieb:
CStoll schrieb:
Xin schrieb:
Das hatten wir doch schon durchgekaut: Flags setzt man nicht mit =, sondern mit |=.
operator = wird protected, damit man die Defaultwerte setzen kann und diejenigen sicher sind, die damit nicht klarkommen.
Zumal die Problematik sowieso erledigt ist, weil der Compiler den Operator mehrdeutig findet.Und wozu gibt's dann die Zuweisung?
Um Default-Werte zu setzen, zum Beispiel bei der Konstruktion.
Den Operator = braucht man eigentlich überhaupt nicht, höchstens um der zu flaggenden Klasse Dinge das Abschalten aller Flaggen und anschließendem Zusetzen der gewünschten Flaggen zu vereinfachen.
Flags in Verbindung mit operator = ist immer risikobehaftet.Und da muß man dann auch aufpassen, welche Teilmenge der Flags man nun tatsächlich erwischt.
Xin schrieb:
CStoll schrieb:
Xin schrieb:
CStoll schrieb:
Genauer: Ich kritisiere das Zusammenwirken von Vererbung und Operatoren - die Operatoren alleine sind brauchbar (mit den Flags als Member), die Vererbungsbeziehung alleine auch (allerdings nicht von Flags, sondern von Flaggable aus), beides zusammen erzeugt unleserlichen - und darum gefährlichen - Code.
Dann nenn die Klasse Flagable.
Mach ich ja, aber der Klasse Flagable würde ich keine Flag-Operatoren geben.
Warum nicht?
Die Klasse Flagable ist kein Flag, also soll sie sich auch nicht wie eins verhalten.
Xin schrieb:
Ich habe keine Fenster in meinem Framework, aber wenn Du mich so fragst, warum sollte ich Fenster nicht von einem Punkt ableiten? Genauer von einem Field, das ist eine positionierte(Point) Fläche (Area).
Wenn du keine Fenster hast, warum reden wir die ganze Zeit über WindowFlags? Der Punkt, auf den ich hinauswollte, ist, daß man theoretisch alles mögliche von allem ableiten könnte - aber ob es Sinn macht, ist die andere Sache. (und bei der Beziehung Fenster->Punkt mußt du auch deutlich machen, wo das Fenster relativ zu seinen Punkt-Koordinaten liegt.
Xin schrieb:
Um ein Fenster zu verschieben setze man entweder den Punkt oder verschiebe es um eine Distance.
Vermutlich würde ich allerdings von Bitmap(abgeleitet von einer BitmapDescription, welche von Area abgeleitet wurde) ableiten und Punkt ableiten und einen operator & Field() erstellen.
Point ObenLinks, UntenRechts; class Window : public Point, public BitMap {} win = Position; // Wo? win = Area( UntenRechts - ObenLinks ); // Wie groß? win += Distance( 10, 10 ); // Ein wenig verschieben. win.DrawBox( Point::Zero, UntenRechts ); win.CopyFrom( CloseIcon, ObenLinks+Distance( 1, 1 ) ); win.DrawLine( Point( 1, CloseIcon.Height+1 ) ), Point(UntenRechts.x-1, CloseIcon.Height+1 ) ); win.DrawText( Point( CloseIcon.Width+1, 1 ), "Mein Fenster" ); printf( "Fenster befindet sich an Position %s, Fläche %s und ist hübsch bemalt.\n", Point( win ).ToString(), Area( win ).ToString() ); screen.CopyFrom( win, win );
Und wer sagt mir, daß operator+= nicht die Fenstergröße korrigiert? Auf den ersten Blick mag das ja ganz nett sein, aber mir ist es trotzdem lieber zu wissen, worauf sich eine Zuweisung bezieht.
Um mal vom Fenster-Beispiel wegzukommen: Würdest du eine Klasse Auto von Farbe, Höchstgeschwindigkeit, Leistung oder aktueller Geschwindigkeit ableiten, nur um "a=rot;" (umlackieren) oder "a+=10;" (beschleunigen? oder doch Motor auswechseln?) schreiben zu können?
Xin schrieb:
CStoll schrieb:
Ja, Integers kann man ver-und-en - aber Integers verwendet man auch nicht als Basis für eigene Klassen, um diese verunden zu können.
Warum eigentlich nicht?
Grade das ist doch die Kritik derer, die das "reine OOP" in C++ suchen.Weil's keinen Sinn macht? Weil C++ keine reine OOP-Sprache ist? Such dir eine Erklärung aus.
Xin schrieb:
CStoll schrieb:
Xin schrieb:
CStoll schrieb:
Daß sie dokumentiert sind, glaube ich dir, aber hast du die ganzen Fallstricke, die du auf den letzten Seiten erfolgreich ignoriert hast (ala "verwende niemals 'if(win)'" oder die möglichen Abhängigkeiten verschiedener Flags) dort ausführlich beschrieben? Wenn nein, wird ziemlich schnell jemand auf die Idee kommen, die "verbotenen" Möglichkeiten auszunutzen.
Wer if( win.Flags ) benutzt wird sowieso gesteinigt, sofern das nicht explizit erlaubt und begründet ist. Sobald da eine Flage hinzugefügt wird, die unabhängig von den Flaggen ist, die damit abgefragt werden wollen, geht das ganze schief. if( win.Flags & KombinationAusGewünschtenFlaggen ) ist wohl Pflicht, selbst wenn das alle existierenden Flaggen sind und der Rest nicht verwendet wird und grundsätzlich auf 0 steht.
if(win.Flags) kann ich explizit verbieten, indem ich den Member privat mache (und nur HasFlag() etc anbiete), dein if(win) kann nur unter Aufwand verboten werden.
Du packst operator bool() als privates Member in Window?
Ich definiere überhaupt keinen operator bool(), wenn ich es vermeiden kann - und wenn, dann so, daß er eine klare Bedeutung hat. Aber du mußt ihn privat definieren, um Konstrukte wie "if(win)..." zu verhindern.
Xin schrieb:
Das ist das Problem... ich brauche keine Regeln - ich brauche Begründungen, warum Regeln existieren. Viele Regeln existieren nämlich nur, weil man das schon immer so gemacht hat.
Das glaube ich in dem Fall nicht, aber es beantwortet nicht die Frage, warum selbst unmögliche Fälle als Möglichkeit erkannt werden, um dann zu argumentieren, dass es mehrdeutig sei.Die Namensauflösung existiert nicht nur für Methoden, sondern für ALLE Namen. Und da ist es mir lieber, eine einheitliche Regel zu haben als ein dickes Paket an Ausnahmen (mal ist es erlaubt, wenn mehrere gleichnamige Gegenstände zusammenprallen, mal nicht).
Sicherlich ist hier eine Gefahr, wenn unwissentlich, mehrere Funktionen gleichen Namens und unterschiedlicher Signatur zusammen kommen, dass man die Basisklassenzugehörigkeit vertauschen könnte. Hier fehlt mir die Möglichkeit, die Zusammenführung aus der Basisklasse heraus explizit zu erlauben, ohne dafür neuen Code zu produzieren.
In meinem Fall ist die Zusammenführung ja gewünscht.Wenn dir so viel daran liegt, kannst du ja mal das ANSI-Kommitee darauf ansprechen - vielleicht nehmen sie deinen Vorschlag in die nächste Standardversion auf, wenn du ihn begründen kannst.
-
CStoll schrieb:
Wenn dir so viel daran liegt, kannst du ja mal das ANSI-Kommitee darauf ansprechen - vielleicht nehmen sie deinen Vorschlag in die nächste Standardversion auf, wenn du ihn begründen kannst.
Nicht eher ISO?
-
CStoll schrieb:
Kennst du das klassische Beispiel der Fehlinterpretiation von "ist-ein"? Jeder Mathematiker wird dir bestätigen, daß ein Quadrat ein Rechteck "ist" - aber aus OOP-Sicht ist es trotzdem falsch,
class quadrat : public rechteck{...}
zu schreiben.Darf man fragen, warum?
edit: Hab nur die ersten zwei Seiten gelesen, hoffe es wurde nicht schon beantwortet (die Antwort scheint ja sowieso glasklar zu sein..).
-
Unfug hier war.
-
CStoll schrieb:
Xin schrieb:
Flags in Verbindung mit operator = ist immer risikobehaftet.
Und da muß man dann auch aufpassen, welche Teilmenge der Flags man nun tatsächlich erwischt.
Das verstehe ich jetzt nicht!?
CStoll schrieb:
Die Klasse Flagable ist kein Flag, also soll sie sich auch nicht wie eins verhalten.
Jow, dem stimme ich zu, allerdings muss man es auch nicht übertreiben. Ob die einzelnen Flags nun in einem Namespace WindowFlag oder mit WindowFlags zusammengefasst werden, spielt meines Erachtens nun keine so große Rolle.
CStoll schrieb:
Xin schrieb:
Ich habe keine Fenster in meinem Framework, aber wenn Du mich so fragst, warum sollte ich Fenster nicht von einem Punkt ableiten? Genauer von einem Field, das ist eine positionierte(Point) Fläche (Area).
Wenn du keine Fenster hast, warum reden wir die ganze Zeit über WindowFlags?
Weil nicht mein Framework das Problem ist, sondern jemand die Frage gestellt, wie man mehrere Bool-Variablen verpacken kann. ^^
CStoll schrieb:
und bei der Beziehung Fenster->Punkt mußt du auch deutlich machen, wo das Fenster relativ zu seinen Punkt-Koordinaten liegt.
Schon wieder verstehe ich Dich nicht!? Wo sollte es denn sonst liegen, wenn nicht da, wo es seine Positionspunkt hat?
CStoll schrieb:
Xin schrieb:
Um ein Fenster zu verschieben setze man entweder den Punkt oder verschiebe es um eine Distance.
Vermutlich würde ich allerdings von Bitmap(abgeleitet von einer BitmapDescription, welche von Area abgeleitet wurde) ableiten und Punkt ableiten und einen operator & Field() erstellen.
win += Distance( 10, 10 ); // Ein wenig verschieben.
Und wer sagt mir, daß operator+= nicht die Fenstergröße korrigiert? Auf den ersten Blick mag das ja ganz nett sein, aber mir ist es trotzdem lieber zu wissen, worauf sich eine Zuweisung bezieht.
Erstens sagt Dir das der Menschenverstand. Wenn Du ein Fenster um eine Distance verschiebst - und nichts anderes ist eine Addition, wenn Du Dir den Zahlenstrahl in der Grundschule in Erinnerung rufst - dass sich das Fenster dann verschiebt.
Wenn Du das nicht intuitiv findest, hilft in der Regel ein Blick in die Klassenhirachie.CStoll schrieb:
Um mal vom Fenster-Beispiel wegzukommen: Würdest du eine Klasse Auto von Farbe, Höchstgeschwindigkeit, Leistung oder aktueller Geschwindigkeit ableiten, nur um "a=rot;" (umlackieren) oder "a+=10;" (beschleunigen? oder doch Motor auswechseln?) schreiben zu können?
Nein, in C++ nicht unbedingt.
Ich würde ein Auto allerdings von Eigenschaften ableiten, die ich mehrfach verwende. So wäre es durchaus möglich, dass ich ein Auto von Farbe ableite, da ich bereits farbverarbeitende Klassen habe, die Farbe von anderen Teilen der Klasse differenzieren.
Sprachlich sind wir da genauso flexibel, wie in der Programmierung.
Ein (einfarbiges) Auto kann eine Farbe sein: "Die Farbe ist rot" => "Das Auto ist rot."
Und natürlich kann ein Auto auch eine Farbe haben: "Die Farbe hat den Wert rot" => "Eine Komponente des Autos ist die rote Farbe."
Sprachlich gehen wir damit also genauso flexibel um.Für Leistung und aktuelle Geschwindigkeit sind bei mir keine Klassen vorhanden. Ich wüßte derzeit auch keinen Grund, derartige Klassen zur Wiederverwertung abstrahieren. Das wären bei mir vermutlich Member.
Grundsätzlich habe ich aber kein Problem damit, bei eindeutigen Aussagen Vererbung zu nutzen.leistung = Leistung( meinAuto ); meinAuto += Geschwindigkeit( 5 ); // Beschleunigen;
Vererbung ist prinzipiell nichts anderes als Membervariablen, Membervariablen entstanden aus der strukturierten Programmierung. Ich halte das Konzept der Membervariablen für sinnvoll, oft auch für richtig, aber in vielerlei Hinsicht ebenso für überholt, denn Vererbung kann Code vereinfachen.
Member halte ich für sinnvoll, wenn sie untergeordnete Objekte enthält.
Autos bestehen aus Sitzen, sie sind aber keine. Sie können eigenständige Eigenschaften besitzen, die in Gleichbehandlung mit dem Auto mehrdeutig sein könnten:langweiligesAuto.Sitze = Farbe( langweiligesAuto );
Farbe wäre hier in einer Vererbungsbeziehung nicht eindeutig. Ein Auto als Sitzmöglichkeit anzusehen, würde ich für akzeptabel halten. Allerdings ist "Sitzmöglichkeit" keine Eigenschaft eines Autos, die unbedingt derart hervorgehoben werden muss. Aber auch das ist subjektiv - meine Oma sieht das anders.
CStoll schrieb:
Xin schrieb:
CStoll schrieb:
Ja, Integers kann man ver-und-en - aber Integers verwendet man auch nicht als Basis für eigene Klassen, um diese verunden zu können.
Warum eigentlich nicht?
Grade das ist doch die Kritik derer, die das "reine OOP" in C++ suchen.Weil's keinen Sinn macht? Weil C++ keine reine OOP-Sprache ist? Such dir eine Erklärung aus.
Ob es keinen Sinn hat, wage ich zu bezweifeln. Die Frage gilt ja auch nicht nach dem Ist-Zustand von C++, sondern einem möglichen Sollte-Zustand.
CStoll schrieb:
Xin schrieb:
CStoll schrieb:
if(win.Flags) kann ich explizit verbieten, indem ich den Member privat mache (und nur HasFlag() etc anbiete), dein if(win) kann nur unter Aufwand verboten werden.
Du packst operator bool() als privates Member in Window?
Ich definiere überhaupt keinen operator bool(), wenn ich es vermeiden kann - und wenn, dann so, daß er eine klare Bedeutung hat. Aber du mußt ihn privat definieren, um Konstrukte wie "if(win)..." zu verhindern.
Und? Wir müssen beide etwas als private deklarieren, um zu verhindern, dass ein Programmierer eine idotische Frage stellen kann. Es gibt diesbezüglich keinen Unterschied zwischen unseren Vorgehen.
Und ganz ehrlich, es gibt eine Grenze, da sichere ich nicht mehr ab. Ich baue keinen Zaun um einen großen Gastank, nur weil auf dem Tank jemand grillen könnte.
Darwin-Awards beweist, dass derartiges gemacht wird und das es tödliche Konsequenzen haben kann.
Ich finde den Kommentar "Kann Nüsse enthalten, bei Nussallergie nicht konsumieren" auf einer Packung Erdnüsse für lächerlich.Wenn ein Programmierer nicht weiß, was es bedeutet alle Flags gleichzeitig abzufragen, obwohl noch unbelegte Flags vorhanden sind (oder könnten), dann darf er gerne auch auf einem Gastank grillen.
Wenn's da knallt, dann sehe ich mich in beiden Fällen nicht in der Verantwortung, da reiche ich guten Gewissens geröstete Erdnüsse zu, ohne nach Allergien zu fragen.CStoll schrieb:
Xin schrieb:
Das ist das Problem... ich brauche keine Regeln - ich brauche Begründungen, warum Regeln existieren. Viele Regeln existieren nämlich nur, weil man das schon immer so gemacht hat.
Das glaube ich in dem Fall nicht, aber es beantwortet nicht die Frage, warum selbst unmögliche Fälle als Möglichkeit erkannt werden, um dann zu argumentieren, dass es mehrdeutig sei.Die Namensauflösung existiert nicht nur für Methoden, sondern für ALLE Namen. Und da ist es mir lieber, eine einheitliche Regel zu haben als ein dickes Paket an Ausnahmen (mal ist es erlaubt, wenn mehrere gleichnamige Gegenstände zusammenprallen, mal nicht).
Solange man auf die Mehrfachvererbung verzichtet, klappt alles wunderbar. Die Mehrfachausnahme sorgt für die Ausnahme.
CStoll schrieb:
Sicherlich ist hier eine Gefahr, wenn unwissentlich, mehrere Funktionen gleichen Namens und unterschiedlicher Signatur zusammen kommen, dass man die Basisklassenzugehörigkeit vertauschen könnte. Hier fehlt mir die Möglichkeit, die Zusammenführung aus der Basisklasse heraus explizit zu erlauben, ohne dafür neuen Code zu produzieren.
In meinem Fall ist die Zusammenführung ja gewünscht.Wenn dir so viel daran liegt, kannst du ja mal das ANSI-Kommitee darauf ansprechen - vielleicht nehmen sie deinen Vorschlag in die nächste Standardversion auf, wenn du ihn begründen kannst.
Für mich ist das Problem durch die Typerweiterung geklärt.
Ich halte C++ für eine der besten Sprachen, die verfügbar sind - und dennoch ist es eine Sprache, die keine Zukunft haben darf, weil zuviele Probleme aus C geerbt wurden.Badestrand schrieb:
CStoll schrieb:
Kennst du das klassische Beispiel der Fehlinterpretiation von "ist-ein"? Jeder Mathematiker wird dir bestätigen, daß ein Quadrat ein Rechteck "ist" - aber aus OOP-Sicht ist es trotzdem falsch,
class quadrat : public rechteck{...}
zu schreiben.Darf man fragen, warum?
Es ist nicht falsch, es ist nur ungeschickt, weil ein Quadrat weniger Informationen benötigt als ein Rechteck. Es wäre aus klassenorientierter Sicht sinnvoller OOP zu verwendenden und ein RechteckInterface zu erstellen, wovon sich Quadrat und Rechteck abzuleiten.
-
Xin schrieb:
Badestrand schrieb:
CStoll schrieb:
Kennst du das klassische Beispiel der Fehlinterpretiation von "ist-ein"? Jeder Mathematiker wird dir bestätigen, daß ein Quadrat ein Rechteck "ist" - aber aus OOP-Sicht ist es trotzdem falsch,
class quadrat : public rechteck{...}
zu schreiben.Darf man fragen, warum?
Es ist nicht falsch, es ist nur ungeschickt, weil ein Quadrat weniger Informationen benötigt als ein Rechteck. Es wäre aus klassenorientierter Sicht sinnvoller OOP zu verwendenden und ein RechteckInterface zu erstellen, wovon sich Quadrat und Rechteck abzuleiten.
Oh, right, danke! Aber nebenbei: Hattet ihr (du und CStoll) nicht erst eine Riesen-Diskussion in einem anderen OOP-Thread? Immer diese ellenlangen Quote-Orgien, ihr kommt doch sowieso auf keinen Nenner
-
Xin schrieb:
CStoll schrieb:
Xin schrieb:
Flags in Verbindung mit operator = ist immer risikobehaftet.
Und da muß man dann auch aufpassen, welche Teilmenge der Flags man nun tatsächlich erwischt.
Das verstehe ich jetzt nicht!?
Wir sind immer noch bei der alten Frage: Setze ich mit "wnd=Window::Modal;" nun das Fullscreen-Flag zurück oder nicht?
Xin schrieb:
CStoll schrieb:
und bei der Beziehung Fenster->Punkt mußt du auch deutlich machen, wo das Fenster relativ zu seinen Punkt-Koordinaten liegt.
Schon wieder verstehe ich Dich nicht!? Wo sollte es denn sonst liegen, wenn nicht da, wo es seine Positionspunkt hat?
Der Punkt ist ziemlich klein im Vergleich zu einem Fenster - also welchen Wert erhalte ich, wenn ich ein Fenster als Punkt betrachte? die linke obere Ecke? die rechte untere Ecke? den Mittelpunkt? ...?
(selbst wenn wir nur von Punkt->Rechteck ausgehen, gibt es mehr als genug Möglichkeiten zu sagen, was "meine" Position sein soll)Xin schrieb:
CStoll schrieb:
Xin schrieb:
Um ein Fenster zu verschieben setze man entweder den Punkt oder verschiebe es um eine Distance.
Vermutlich würde ich allerdings von Bitmap(abgeleitet von einer BitmapDescription, welche von Area abgeleitet wurde) ableiten und Punkt ableiten und einen operator & Field() erstellen.
win += Distance( 10, 10 ); // Ein wenig verschieben.
Und wer sagt mir, daß operator+= nicht die Fenstergröße korrigiert? Auf den ersten Blick mag das ja ganz nett sein, aber mir ist es trotzdem lieber zu wissen, worauf sich eine Zuweisung bezieht.
Erstens sagt Dir das der Menschenverstand. Wenn Du ein Fenster um eine Distance verschiebst - und nichts anderes ist eine Addition, wenn Du Dir den Zahlenstrahl in der Grundschule in Erinnerung rufst - dass sich das Fenster dann verschiebt.
Wenn Du das nicht intuitiv findest, hilft in der Regel ein Blick in die Klassenhirachie.Ja, ich muß wieder nachsehen - und das notfalls über mehrere Dateien hinweg, bis ich den richtigen op+= für meinen Zweck finde.
Xin schrieb:
CStoll schrieb:
Um mal vom Fenster-Beispiel wegzukommen: Würdest du eine Klasse Auto von Farbe, Höchstgeschwindigkeit, Leistung oder aktueller Geschwindigkeit ableiten, nur um "a=rot;" (umlackieren) oder "a+=10;" (beschleunigen? oder doch Motor auswechseln?) schreiben zu können?
Nein, in C++ nicht unbedingt.
Ich würde ein Auto allerdings von Eigenschaften ableiten, die ich mehrfach verwende. So wäre es durchaus möglich, dass ich ein Auto von Farbe ableite, da ich bereits farbverarbeitende Klassen habe, die Farbe von anderen Teilen der Klasse differenzieren.
Sprachlich sind wir da genauso flexibel, wie in der Programmierung.
Ein (einfarbiges) Auto kann eine Farbe sein: "Die Farbe ist rot" => "Das Auto ist rot."
Und natürlich kann ein Auto auch eine Farbe haben: "Die Farbe hat den Wert rot" => "Eine Komponente des Autos ist die rote Farbe."
Sprachlich gehen wir damit also genauso flexibel um.Ja, die Sprache kann manchmal recht mehrdeutig sein - und niemanden stört's
Aber aus OOP-Sicht ist die Vererbung von Farbe->Auto trotzdem Käse. (und um ein Auto an eine farbverarbeitende Funktion zu übergeben, ist eine Typumwandlung über 'operator Farbe()' besser geeignet).
Xin schrieb:
Für Leistung und aktuelle Geschwindigkeit sind bei mir keine Klassen vorhanden. Ich wüßte derzeit auch keinen Grund, derartige Klassen zur Wiederverwertung abstrahieren. Das wären bei mir vermutlich Member.
Grundsätzlich habe ich aber kein Problem damit, bei eindeutigen Aussagen Vererbung zu nutzen.leistung = Leistung( meinAuto ); meinAuto += Geschwindigkeit( 5 ); // Beschleunigen;
Vererbung ist prinzipiell nichts anderes als Membervariablen, Membervariablen entstanden aus der strukturierten Programmierung. Ich halte das Konzept der Membervariablen für sinnvoll, oft auch für richtig, aber in vielerlei Hinsicht ebenso für überholt, denn Vererbung kann Code vereinfachen.
Vererbung ist keine verkappte Member-Beziehung - mit der Vererbung gehst du auch einen Vertrag ein, das Interface der Basisklasse konsistent umzusetzen. (und außerdem hat ein Auto zwei Geschwindigkeiten - die aktuelle und die maximale - wie willst du das per Vererbung darstellen?
Xin schrieb:
Member halte ich für sinnvoll, wenn sie untergeordnete Objekte enthält.
Autos bestehen aus Sitzen, sie sind aber keine. Sie können eigenständige Eigenschaften besitzen, die in Gleichbehandlung mit dem Auto mehrdeutig sein könnten:langweiligesAuto.Sitze = Farbe( langweiligesAuto );
Farbe wäre hier in einer Vererbungsbeziehung nicht eindeutig. Ein Auto als Sitzmöglichkeit anzusehen, würde ich für akzeptabel halten. Allerdings ist "Sitzmöglichkeit" keine Eigenschaft eines Autos, die unbedingt derart hervorgehoben werden muss. Aber auch das ist subjektiv - meine Oma sieht das anders.
Wie du inzwischen bemerkt hast, nicht nur die
Xin schrieb:
CStoll schrieb:
Xin schrieb:
CStoll schrieb:
Ja, Integers kann man ver-und-en - aber Integers verwendet man auch nicht als Basis für eigene Klassen, um diese verunden zu können.
Warum eigentlich nicht?
Grade das ist doch die Kritik derer, die das "reine OOP" in C++ suchen.Weil's keinen Sinn macht? Weil C++ keine reine OOP-Sprache ist? Such dir eine Erklärung aus.
Ob es keinen Sinn hat, wage ich zu bezweifeln. Die Frage gilt ja auch nicht nach dem Ist-Zustand von C++, sondern einem möglichen Sollte-Zustand.
Dann gib mir doch mal ein sinnvolles Beispiel, um von int ableiten zu müssen.
(und zur Not kannt du auch eine echte OOP-Sprache verwenden, wie z.B. Java (Oops- da kann man ja auch nicht von Integer ableiten
))
Xin schrieb:
CStoll schrieb:
Xin schrieb:
CStoll schrieb:
if(win.Flags) kann ich explizit verbieten, indem ich den Member privat mache (und nur HasFlag() etc anbiete), dein if(win) kann nur unter Aufwand verboten werden.
Du packst operator bool() als privates Member in Window?
Ich definiere überhaupt keinen operator bool(), wenn ich es vermeiden kann - und wenn, dann so, daß er eine klare Bedeutung hat. Aber du mußt ihn privat definieren, um Konstrukte wie "if(win)..." zu verhindern.
Und? Wir müssen beide etwas als private deklarieren, um zu verhindern, dass ein Programmierer eine idotische Frage stellen kann. Es gibt diesbezüglich keinen Unterschied zwischen unseren Vorgehen.
Der Unterschied ist konzeptionell: Ich deklariere die Flag von vornherein privat, weil ihre Existenz und Aufbau nichts im offiziellen Interface zu suchen haben. Du mußt deinen Umwandlungsoperator privat nachträglich privat deklarieren, um unsinnige Verwendungen zu verhindern.
Und damit sind wir doch wieder bei der Rechteck-Quadrat-Problematik angekommen: Du sagst: "ein Fenster ist ein Flag", "ein Flag kann nach bool konvertiert werden" und "ein Fenster kann nicht nach bool konvertiert werden" - siehst du den Widerspruch in diesen Aussagen?
Xin schrieb:
Und ganz ehrlich, es gibt eine Grenze, da sichere ich nicht mehr ab. Ich baue keinen Zaun um einen großen Gastank, nur weil auf dem Tank jemand grillen könnte.
Darwin-Awards beweist, dass derartiges gemacht wird und das es tödliche Konsequenzen haben kann.
Ich finde den Kommentar "Kann Nüsse enthalten, bei Nussallergie nicht konsumieren" auf einer Packung Erdnüsse für lächerlich.Du bist ja auch kein Allergiker.
Xin schrieb:
CStoll schrieb:
Xin schrieb:
Das ist das Problem... ich brauche keine Regeln - ich brauche Begründungen, warum Regeln existieren. Viele Regeln existieren nämlich nur, weil man das schon immer so gemacht hat.
Das glaube ich in dem Fall nicht, aber es beantwortet nicht die Frage, warum selbst unmögliche Fälle als Möglichkeit erkannt werden, um dann zu argumentieren, dass es mehrdeutig sei.Die Namensauflösung existiert nicht nur für Methoden, sondern für ALLE Namen. Und da ist es mir lieber, eine einheitliche Regel zu haben als ein dickes Paket an Ausnahmen (mal ist es erlaubt, wenn mehrere gleichnamige Gegenstände zusammenprallen, mal nicht).
Solange man auf die Mehrfachvererbung verzichtet, klappt alles wunderbar. Die Mehrfachausnahme sorgt für die Ausnahme.
Dann vergleiche mal die Fälle, wo Namen zusammenprallen legal könnten, mit denen, wo es ein Fehler ist. Das dürfte eine relativ lange Liste von Fallunterscheidungen zwischen "erlaubt" (z.B. zwei Funktionen mit unterschiedlicher Signatur), "nicht erlaubt" (z.B. zwei Member) und "gelegentlich erlaubt" (z.B. Funktion vs. Member) ergeben - viel Spaß dabei, alle Fälle herauszufischen und zu implementieren.
Xin schrieb:
CStoll schrieb:
Sicherlich ist hier eine Gefahr, wenn unwissentlich, mehrere Funktionen gleichen Namens und unterschiedlicher Signatur zusammen kommen, dass man die Basisklassenzugehörigkeit vertauschen könnte. Hier fehlt mir die Möglichkeit, die Zusammenführung aus der Basisklasse heraus explizit zu erlauben, ohne dafür neuen Code zu produzieren.
In meinem Fall ist die Zusammenführung ja gewünscht.Wenn dir so viel daran liegt, kannst du ja mal das ANSI-Kommitee darauf ansprechen - vielleicht nehmen sie deinen Vorschlag in die nächste Standardversion auf, wenn du ihn begründen kannst.
Für mich ist das Problem durch die Typerweiterung geklärt.
Ich halte C++ für eine der besten Sprachen, die verfügbar sind - und dennoch ist es eine Sprache, die keine Zukunft haben darf, weil zuviele Probleme aus C geerbt wurden.Ja, die Typerweiterung ist gut - aber wie bereits geklärt wurde, kannst du die nicht effektiv mit Vererbung nachbilden. (und Sprachmittel 1:1 zwischen verschiedenen Sprachen umrechnen zu wollen ist sowieso unmöglich)
Badestrand schrieb:
CStoll schrieb:
Kennst du das klassische Beispiel der Fehlinterpretiation von "ist-ein"? Jeder Mathematiker wird dir bestätigen, daß ein Quadrat ein Rechteck "ist" - aber aus OOP-Sicht ist es trotzdem falsch,
class quadrat : public rechteck{...}
zu schreiben.Darf man fragen, warum?
Bei einer Vererbung darf man (aus OOP-Sicht) die Eigenschaften der Basisklasse nicht einschränken, sondern nur erweitern - Rechteck hat eine SetWidth() und SetHeight(), die jeweils eine Ausdehnung ändern können, Quadrat sichert zu, daß beide Seiten gleich lang sind - d.h. egal wie du SetWidth() implementierst, zerstörst du damit entweder die Invarianten des Rechtecks oder des Quadrats:
void resize(rectangle& r) { r.SetWidth(10); r.SetHeight(5); ASSERT(r.GetWidth()==10 && r.GetHeight()==5);//entweder dieser Assert fliegt dir um die Ohren } int main() { quadrat q; resize(q); ASSERT(q.GetWidth()==q.GetHeight());//oder dieser }
-
car+=10;
oder
win += rect;
Das ist doch mal eindeutig was es macht
Ich habe lange Zeit nicht verstanden warum Leute gegen Operatoren-Überladung sein können - nun weiß ich es...
-
Badestrand schrieb:
Oh, right, danke! Aber nebenbei: Hattet ihr (du und CStoll) nicht erst eine Riesen-Diskussion in einem anderen OOP-Thread? Immer diese ellenlangen Quote-Orgien, ihr kommt doch sowieso auf keinen Nenner
CStoll war an der Diskussion eigentlich nicht in der Form beteiligt. Auf einen Nenner sind kam man in der anderen Diskussion aber auch nicht.
Andererseits - wozu ist so ein Forum da? Man diskutiert mit anderen über Lösungen von Programmierproblemen und das tun CStoll und ich hier.CStoll schrieb:
Wir sind immer noch bei der alten Frage: Setze ich mit "wnd=Window::Modal;" nun das Fullscreen-Flag zurück oder nicht?
Hatte ich das nicht schon mehrfach als No-Go-Befehl geoutet, den ich für Dich extra als private setzte?
Ergo setzt wnd=Winodw::Modal den Compiler zurück und der dankt es mit einer Fehlermeldung.CStoll schrieb:
Der Punkt ist ziemlich klein im Vergleich zu einem Fenster - also welchen Wert erhalte ich, wenn ich ein Fenster als Punkt betrachte? die linke obere Ecke? die rechte untere Ecke? den Mittelpunkt? ...?
(selbst wenn wir nur von Punkt->Rechteck ausgehen, gibt es mehr als genug Möglichkeiten zu sagen, was "meine" Position sein soll)Sorry, aber das wird hier lächerlich. Jedes OS muss die Konvention machen, dass eine Punkt die Position eines Fensters angibt. Bei allem, was ich bisher dazwischen hatte, ist das der Punkt, an dem das Fenster liegt/beginnt. Ausgehend vom Koordinatensystem, das Oben-Links beginnt war das bisher immer der linke obere Punkt.
CStoll schrieb:
Xin schrieb:
Erstens sagt Dir das der Menschenverstand. Wenn Du ein Fenster um eine Distance verschiebst - und nichts anderes ist eine Addition, wenn Du Dir den Zahlenstrahl in der Grundschule in Erinnerung rufst - dass sich das Fenster dann verschiebt.
Wenn Du das nicht intuitiv findest, hilft in der Regel ein Blick in die Klassenhirachie.Ja, ich muß wieder nachsehen - und das notfalls über mehrere Dateien hinweg, bis ich den richtigen op+= für meinen Zweck finde.
Ich weiß nicht, wie Du das machst, wenn Du mit einem Framework arbeitest. Macht es plopp und Du weißt, wie die Frameworks arbeiten? Ich muss da am Anfang immer mal in die Dokumentation sehen, um mich einzuarbeiten. Sobald das geschehen ist, brauche ich nicht mehr nachzuschlagen.
Das ganze wird wirklich lächerlich. Du bringst hier Punkte an, die für Membervariablen, genauso wie für Vererbung gelten und behauptest, es wäre ein Problem bei Vererbung. Du musst Deine Variable Private erklären, ich meinen operator, um einer Frage vorzubeugen, für die der Entwickler gesteinigt gehört. Und dass man, wenn man keine Ahnung hat, auch mal in die Doku gucken muss, gefällt Dir auch nicht.Sorry, Du kannst auch gerne in die Kerbe "Xin ignoriert Argumente" hauen, wenn Du nur recht haben möchtest, aber ich sehe hier keine Argumente. Was ich sehe ist, dass ich bereit bin Dinge anders zu machen, als üblich und die Bereitschaft sich in die Richtung mit dem Thema zu beschäftigen sagen wir zurückhaltend ist.
CStoll schrieb:
Xin schrieb:
Ich würde ein Auto allerdings von Eigenschaften ableiten, die ich mehrfach verwende. Sprachlich sind wir da genauso flexibel, wie in der Programmierung.
Ein (einfarbiges) Auto kann eine Farbe sein: "Die Farbe ist rot" => "Das Auto ist rot."
Und natürlich kann ein Auto auch eine Farbe haben: "Die Farbe hat den Wert rot" => "Eine Komponente des Autos ist die rote Farbe."Ja, die Sprache kann manchmal recht mehrdeutig sein - und niemanden stört's
Aber aus OOP-Sicht ist die Vererbung von Farbe->Auto trotzdem Käse. (und um ein Auto an eine farbverarbeitende Funktion zu übergeben, ist eine Typumwandlung über 'operator Farbe()' besser geeignet).
Behauptung. Begründung?
CStoll schrieb:
Xin schrieb:
Für Leistung und aktuelle Geschwindigkeit sind bei mir keine Klassen vorhanden. Ich wüßte derzeit auch keinen Grund, derartige Klassen zur Wiederverwertung abstrahieren. Das wären bei mir vermutlich Member.
Grundsätzlich habe ich aber kein Problem damit, bei eindeutigen Aussagen Vererbung zu nutzen.leistung = Leistung( meinAuto ); meinAuto += Geschwindigkeit( 5 ); // Beschleunigen;
Vererbung ist prinzipiell nichts anderes als Membervariablen, Membervariablen entstanden aus der strukturierten Programmierung. Ich halte das Konzept der Membervariablen für sinnvoll, oft auch für richtig, aber in vielerlei Hinsicht ebenso für überholt, denn Vererbung kann Code vereinfachen.
Vererbung ist keine verkappte Member-Beziehung - mit der Vererbung gehst du auch einen Vertrag ein, das Interface der Basisklasse konsistent umzusetzen. (und außerdem hat ein Auto zwei Geschwindigkeiten - die aktuelle und die maximale - wie willst du das per Vererbung darstellen?
class VMax.: public V {}
class VCurrent : public V {}Nebenher... was soll das eigentlich? Ich sagte gleich zu Beginn, dass ich das nicht unbedingt als Klassen beschreiben würde.
Allerdings muss ich sagen, dass je mehr Du dagegen argumentierst, desto mehr gefällt mir der Ansatz, Eigenschaften in Klassen zu kapseln.CStoll schrieb:
Xin schrieb:
Member halte ich für sinnvoll, wenn sie untergeordnete Objekte enthält.
Autos bestehen aus Sitzen, sie sind aber keine. Sie können eigenständige Eigenschaften besitzen, die in Gleichbehandlung mit dem Auto mehrdeutig sein könnten:langweiligesAuto.Sitze = Farbe( langweiligesAuto );
Farbe wäre hier in einer Vererbungsbeziehung nicht eindeutig. Ein Auto als Sitzmöglichkeit anzusehen, würde ich für akzeptabel halten. Allerdings ist "Sitzmöglichkeit" keine Eigenschaft eines Autos, die unbedingt derart hervorgehoben werden muss. Aber auch das ist subjektiv - meine Oma sieht das anders.
Wie du inzwischen bemerkt hast, nicht nur die
Du siehst ein Auto auch als Sitzgelegenheit? Was beschwerst Du Dich dann? :->
Nur für den Fall, dass Du es nicht gesehen hast: Die Sitze in einem Auto beschreiben wunderbar genau das, was ich als Member ("besteht-aus") beschreiben würde, denn ein Auto verhält sich nicht wie ein Sitz und ist auch kein Sitz.
CStoll schrieb:
Xin schrieb:
CStoll schrieb:
Xin schrieb:
CStoll schrieb:
Ja, Integers kann man ver-und-en - aber Integers verwendet man auch nicht als Basis für eigene Klassen, um diese verunden zu können.
Warum eigentlich nicht?
Grade das ist doch die Kritik derer, die das "reine OOP" in C++ suchen.Weil's keinen Sinn macht? Weil C++ keine reine OOP-Sprache ist? Such dir eine Erklärung aus.
Ob es keinen Sinn hat, wage ich zu bezweifeln. Die Frage gilt ja auch nicht nach dem Ist-Zustand von C++, sondern einem möglichen Sollte-Zustand.
Dann gib mir doch mal ein sinnvolles Beispiel, um von int ableiten zu müssen.
(und zur Not kannt du auch eine echte OOP-Sprache verwenden, wie z.B. Java (Oops- da kann man ja auch nicht von Integer ableiten
))
Ja, und weil man es in C++ nicht kann, und weil man es in Java nicht kann, ist es eine dumme Idee von einem derartigen Typ abzuleiten, hmm?
class Pixel : public int {} class PixelWidth : public Pixel {} class PixelHeight : public Pixel {} class Area : public PixelWidth, public PixelHeight class BitsPerSample : public int {} class BitmapArea : public PixelWidth, public PixelHeight, public BitPerSample {} class DigiCam : public BitMapArea {} int GetMegaPixel( Area a ) { return PixelWidth( a ) * PixelHeight( a ); } DigiCam myCam; // Fill myCam printf( "%d\n", GetMegaPixel( myCam ) );
Die Tatsache, dass sich das alles mit Membervariablen lösen lässt, bedeutet nicht, dass diese Methode schlecht wäre. Dieser Sourcecode beschreibt nichts anderes als den Zugriff auf Membervariablen.
Man sollte Vererbung nicht nur als eine "ist-ein" betrachten, sondern auch sehen, dass hier eigenständige Eigenschaften zusammengebracht werden können, die eine Klasse ausmachen.Wo ich Dir recht gebe, ist dass C++ wenig Möglichkeiten bietet exakt zwischen "ist-ein" und "verhält-sich-als" zu unterscheiden. Ein "verhält-sich-als" muss selbst implementiert werden und kann nicht von einer Eigenschaft übernommen werden.
CStoll schrieb:
Der Unterschied ist konzeptionell: Ich deklariere die Flag von vornherein privat, weil ihre Existenz und Aufbau nichts im offiziellen Interface zu suchen haben. Du mußt deinen Umwandlungsoperator privat nachträglich privat deklarieren, um unsinnige Verwendungen zu verhindern.
Shade sagte, Schreibarbeit zählt nicht. Ich sagte, dass meine Methode im Aufbau erstmal mehr als weniger Schreibarbeit ist.
So what? Ich will mit WindowFlags Window implementieren, das heißt ich muss das Zusammenspiel der Klassen organisieren, und das ist problemlos machbar.Das einzige, was für mich zählt ist, wie man mit den Klassen umgehen kann, wenn sie erstmal implementiert sind.
Notfalls packe ich Dir sämtliche Flags nochmals als private in die Windowklasse, da habe ich kein Problem mit. Mir ist wichtig, dass ich garantieren kann, dass Eigenschaften zwangsläufig immer den gleichen Namen haben. Den Namen einer Eigenschaftsklasse kann ich nicht von Klasse zu Klasse ändern, den Namen einer Membervariablen schon. Das über ein Framework immer konstant zu halten, ist eine Sache, die viel mehr Disziplin verlangt, als derartige Klassen einmalig sehr ausführlich beschreiben zu müssen.CStoll schrieb:
Und damit sind wir doch wieder bei der Rechteck-Quadrat-Problematik angekommen: Du sagst: "ein Fenster ist ein Flag", "ein Flag kann nach bool konvertiert werden" und "ein Fenster kann nicht nach bool konvertiert werden" - siehst du den Widerspruch in diesen Aussagen?
Ich sagte ein Window ist eine Erweiterung zu WindowFlags und kann zu WindowFlags konvertiert werden.
Den operator bool habe ich auf Deinen Wunsch für Deppenprogrammierer jetzt private gesetzt, weil ich zustimme, dass ein Fenster kein bool ist.
Auch wenn Du es noch 10mal wiederholst, noch privater kann ich's nicht setzen. Das Problem, welches keins sein darf, weil kein denkender Entwicker diese Frage stellen darf, ist selbst für die nicht denkenden gelöst. Darauf rumzureiten, bringt uns also nicht weiter. Es ist punktuell gelöst und muss nie wieder gelöst werden.CStoll schrieb:
Xin schrieb:
Und ganz ehrlich, es gibt eine Grenze, da sichere ich nicht mehr ab. Ich baue keinen Zaun um einen großen Gastank, nur weil auf dem Tank jemand grillen könnte.
Darwin-Awards beweist, dass derartiges gemacht wird und das es tödliche Konsequenzen haben kann.
Ich finde den Kommentar "Kann Nüsse enthalten, bei Nussallergie nicht konsumieren" auf einer Packung Erdnüsse für lächerlich.Du bist ja auch kein Allergiker.
Doch. Ich bin allergisch gegen Roggen- und Graspollen. Ich vermeide zu gewissen Zeiten Grasflächen und Rasenmäher, obwohl da kein Schild steht "Für Grasallergiker zur Pollensaison nicht geeignet.". Da muss man mich nicht drauf hinweisen. Ich binde mir kein Startrakete auf's Autodach, nur weil da kein Aufkleber "nur als Starthilfe für Jets einsetzen" draufsteht.
Es gibt denkende Menschen und es gibt Menschen, die nicht denken. Und dann gibt es noch die Evolution und beides greift ineinander. Und das ist gut so...Shade Of Mine schrieb:
car+=10;
oder
win += rect;
Das ist doch mal eindeutig was es macht
Ich habe lange Zeit nicht verstanden warum Leute gegen Operatoren-Überladung sein können - nun weiß ich es...
Derartige Überladung beschreibe ich hier nicht. Bei mir steht z.B. "car += Geschwindigkeit( 10 );". Die Gefahr besteht vorrangig mit untypisierten Daten, wie eben int, die für so ziemlich alles gebraucht werden. Addiere ich einen aussagekräftigen Datentyp, ist die Handlung genauso ersichtlich, wie der Name des Datentyps.
Ich verteufle nicht eine Möglichkeit, weil sie falsch angewendet werden kann. Ich verteufle die Leute, die Möglichkeiten unüberlegt falsch anwenden. Wer Möglichkeiten absichtlich falsch anwendet, nur um sie schlecht zu machen, der sollte sich vielleicht mal mit den guten Seiten beschäftigen.
Und nebenher: Wer gegen Operatoren-Überladung ist, muss zwangsläufig auch gegen Funktionsüberladung sein, denn nichts anderes ist die operator-Überladung.
-
Xin schrieb:
CStoll schrieb:
Wir sind immer noch bei der alten Frage: Setze ich mit "wnd=Window::Modal;" nun das Fullscreen-Flag zurück oder nicht?
Hatte ich das nicht schon mehrfach als No-Go-Befehl geoutet, den ich für Dich extra als private setzte?
Ergo setzt wnd=Winodw::Modal den Compiler zurück und der dankt es mit einer Fehlermeldung.Was denn nun - auf der einen Seite bietest du einen operator= mit der Semantik "setze alle Flags zurück und stelle dann Flag xyz ein", auf der anderen Seite erklärst du mir, daß es keinen solchen Operator gibt. Entscheide dich bitte.
Xin schrieb:
CStoll schrieb:
Der Punkt ist ziemlich klein im Vergleich zu einem Fenster - also welchen Wert erhalte ich, wenn ich ein Fenster als Punkt betrachte? die linke obere Ecke? die rechte untere Ecke? den Mittelpunkt? ...?
(selbst wenn wir nur von Punkt->Rechteck ausgehen, gibt es mehr als genug Möglichkeiten zu sagen, was "meine" Position sein soll)Sorry, aber das wird hier lächerlich. Jedes OS muss die Konvention machen, dass eine Punkt die Position eines Fensters angibt. Bei allem, was ich bisher dazwischen hatte, ist das der Punkt, an dem das Fenster liegt/beginnt. Ausgehend vom Koordinatensystem, das Oben-Links beginnt war das bisher immer der linke obere Punkt.
Aber in einem vernünftigen Design gibt der Name einer Eigenschaft an, was sie bedeutet - wenn ich einen Member "Point center;" oder "Point upperleft;" habe, kann ich daraus herleiten, wie das Fenster dazu liegt. Die Vererbungsbeziehung hat keinen Namen, also muß diese Zuordnung anders dokumentiert werden.
Xin schrieb:
CStoll schrieb:
Xin schrieb:
Ich würde ein Auto allerdings von Eigenschaften ableiten, die ich mehrfach verwende. Sprachlich sind wir da genauso flexibel, wie in der Programmierung.
Ein (einfarbiges) Auto kann eine Farbe sein: "Die Farbe ist rot" => "Das Auto ist rot."
Und natürlich kann ein Auto auch eine Farbe haben: "Die Farbe hat den Wert rot" => "Eine Komponente des Autos ist die rote Farbe."Ja, die Sprache kann manchmal recht mehrdeutig sein - und niemanden stört's
Aber aus OOP-Sicht ist die Vererbung von Farbe->Auto trotzdem Käse. (und um ein Auto an eine farbverarbeitende Funktion zu übergeben, ist eine Typumwandlung über 'operator Farbe()' besser geeignet).
Behauptung. Begründung?
Hast du schonmal versucht, dein Haus mit einem Auto zu lackieren? Wenn ja, was ist dabei herausgekommen?
Xin schrieb:
CStoll schrieb:
Xin schrieb:
Für Leistung und aktuelle Geschwindigkeit sind bei mir keine Klassen vorhanden. Ich wüßte derzeit auch keinen Grund, derartige Klassen zur Wiederverwertung abstrahieren. Das wären bei mir vermutlich Member.
Grundsätzlich habe ich aber kein Problem damit, bei eindeutigen Aussagen Vererbung zu nutzen.leistung = Leistung( meinAuto ); meinAuto += Geschwindigkeit( 5 ); // Beschleunigen;
Vererbung ist prinzipiell nichts anderes als Membervariablen, Membervariablen entstanden aus der strukturierten Programmierung. Ich halte das Konzept der Membervariablen für sinnvoll, oft auch für richtig, aber in vielerlei Hinsicht ebenso für überholt, denn Vererbung kann Code vereinfachen.
Vererbung ist keine verkappte Member-Beziehung - mit der Vererbung gehst du auch einen Vertrag ein, das Interface der Basisklasse konsistent umzusetzen. (und außerdem hat ein Auto zwei Geschwindigkeiten - die aktuelle und die maximale - wie willst du das per Vererbung darstellen?
class VMax.: public V {}
class VCurrent : public V {}Nebenher... was soll das eigentlich? Ich sagte gleich zu Beginn, dass ich das nicht unbedingt als Klassen beschreiben würde.
Allerdings muss ich sagen, dass je mehr Du dagegen argumentierst, desto mehr gefällt mir der Ansatz, Eigenschaften in Klassen zu kapseln.Wo du ständig auf Kürze rumreitest - was ist der Unterschied zwischen "c = VCurrent(v);" und "c.VCurrent = v;"? Ich finde jedenfalls letzeres klarer.
Xin schrieb:
CStoll schrieb:
Xin schrieb:
Member halte ich für sinnvoll, wenn sie untergeordnete Objekte enthält.
Autos bestehen aus Sitzen, sie sind aber keine. Sie können eigenständige Eigenschaften besitzen, die in Gleichbehandlung mit dem Auto mehrdeutig sein könnten:langweiligesAuto.Sitze = Farbe( langweiligesAuto );
Farbe wäre hier in einer Vererbungsbeziehung nicht eindeutig. Ein Auto als Sitzmöglichkeit anzusehen, würde ich für akzeptabel halten. Allerdings ist "Sitzmöglichkeit" keine Eigenschaft eines Autos, die unbedingt derart hervorgehoben werden muss. Aber auch das ist subjektiv - meine Oma sieht das anders.
Wie du inzwischen bemerkt hast, nicht nur die
Du siehst ein Auto auch als Sitzgelegenheit? Was beschwerst Du Dich dann? :->
Nein, aber ich sehe ein Auto auch nicht als Geschwindigkeit an
Xin schrieb:
Nur für den Fall, dass Du es nicht gesehen hast: Die Sitze in einem Auto beschreiben wunderbar genau das, was ich als Member ("besteht-aus") beschreiben würde, denn ein Auto verhält sich nicht wie ein Sitz und ist auch kein Sitz.
Ein Auto verhält sich auch nicht wie eine Geschwindigkeit (kann die sich überhaupt verhalten?) - ein Auto hat eine Geschwindigkeit. (ja, die Beziehung Auto<->Geschwindigkeit ist etwas technisch anderes als Auto<->Sitz oder Auto<->Motor, aber sie liegt definitiv näher an "hat-ein" als an "ist-ein")
Xin schrieb:
CStoll schrieb:
Xin schrieb:
CStoll schrieb:
Xin schrieb:
CStoll schrieb:
Ja, Integers kann man ver-und-en - aber Integers verwendet man auch nicht als Basis für eigene Klassen, um diese verunden zu können.
Warum eigentlich nicht?
Grade das ist doch die Kritik derer, die das "reine OOP" in C++ suchen.Weil's keinen Sinn macht? Weil C++ keine reine OOP-Sprache ist? Such dir eine Erklärung aus.
Ob es keinen Sinn hat, wage ich zu bezweifeln. Die Frage gilt ja auch nicht nach dem Ist-Zustand von C++, sondern einem möglichen Sollte-Zustand.
Dann gib mir doch mal ein sinnvolles Beispiel, um von int ableiten zu müssen.
(und zur Not kannt du auch eine echte OOP-Sprache verwenden, wie z.B. Java (Oops- da kann man ja auch nicht von Integer ableiten
))
Ja, und weil man es in C++ nicht kann, und weil man es in Java nicht kann, ist es eine dumme Idee von einem derartigen Typ abzuleiten, hmm?
class Pixel : public int {} class PixelWidth : public Pixel {} class PixelHeight : public Pixel {} class Area : public PixelWidth, public PixelHeight class BitsPerSample : public int {} class BitmapArea : public PixelWidth, public PixelHeight, public BitPerSample {} class DigiCam : public BitMapArea {} int GetMegaPixel( Area a ) { return PixelWidth( a ) * PixelHeight( a ); } DigiCam myCam; // Fill myCam printf( "%d\n", GetMegaPixel( myCam ) );
Die Tatsache, dass sich das alles mit Membervariablen lösen lässt, bedeutet nicht, dass diese Methode schlecht wäre. Dieser Sourcecode beschreibt nichts anderes als den Zugriff auf Membervariablen.
Und was hast du davon? Kiloweise Hilfsklassen, die nichts anderes machen, als 'int' einen neuen Namen zu geben. In der Anwendung ist sowas bestenfalls gewöhnungsbedürftig - und schlimmstenfalls füllst du dir den globalen Namensraum mit Bezeichnern, die nur in Zusammenwirken mit deinen Klassen eine Bedeutung haben.
Xin schrieb:
Man sollte Vererbung nicht nur als eine "ist-ein" betrachten, sondern auch sehen, dass hier eigenständige Eigenschaften zusammengebracht werden können, die eine Klasse ausmachen.
Vererbung in C++ stellt nunmal eine "ist-ein"-Beziehung dar - auch wenn du dich auf den Kopf stellst, mußt du andere Anwendungen erst einmal begründen.
Xin schrieb:
CStoll schrieb:
Der Unterschied ist konzeptionell: Ich deklariere die Flag von vornherein privat, weil ihre Existenz und Aufbau nichts im offiziellen Interface zu suchen haben. Du mußt deinen Umwandlungsoperator privat nachträglich privat deklarieren, um unsinnige Verwendungen zu verhindern.
Shade sagte, Schreibarbeit zählt nicht. Ich sagte, dass meine Methode im Aufbau erstmal mehr als weniger Schreibarbeit ist.
So what? Ich will mit WindowFlags Window implementieren, das heißt ich muss das Zusammenspiel der Klassen organisieren, und das ist problemlos machbar.Das einzige, was für mich zählt ist, wie man mit den Klassen umgehen kann, wenn sie erstmal implementiert sind.
Notfalls packe ich Dir sämtliche Flags nochmals als private in die Windowklasse, da habe ich kein Problem mit. Mir ist wichtig, dass ich garantieren kann, dass Eigenschaften zwangsläufig immer den gleichen Namen haben. Den Namen einer Eigenschaftsklasse kann ich nicht von Klasse zu Klasse ändern, den Namen einer Membervariablen schon. Das über ein Framework immer konstant zu halten, ist eine Sache, die viel mehr Disziplin verlangt, als derartige Klassen einmalig sehr ausführlich beschreiben zu müssen.Die Namen der öffentlichen Schnittstelle werden auch in der Hierarchie durchgereicht, also wo siehst du das Problem? (wie die privaten Member heißen, geht niemanden außerhalb der Klasse etwas an, also ist da auch keine Konsistenz erforderlich)
Xin schrieb:
CStoll schrieb:
Und damit sind wir doch wieder bei der Rechteck-Quadrat-Problematik angekommen: Du sagst: "ein Fenster ist ein Flag", "ein Flag kann nach bool konvertiert werden" und "ein Fenster kann nicht nach bool konvertiert werden" - siehst du den Widerspruch in diesen Aussagen?
Ich sagte ein Window ist eine Erweiterung zu WindowFlags und kann zu WindowFlags konvertiert werden.
Den operator bool habe ich auf Deinen Wunsch für Deppenprogrammierer jetzt private gesetzt, weil ich zustimme, dass ein Fenster kein bool ist.
Auch wenn Du es noch 10mal wiederholst, noch privater kann ich's nicht setzen. Das Problem, welches keins sein darf, weil kein denkender Entwicker diese Frage stellen darf, ist selbst für die nicht denkenden gelöst. Darauf rumzureiten, bringt uns also nicht weiter. Es ist punktuell gelöst und muss nie wieder gelöst werden.Ja, das Problem hast du gelöst, aber damit die "ist-ein"-Beziehung zwischen WindowFlags und Window ausgehebelt. Wenn Window ein WindowFlags ist, muß es auch alles können, was ein WindowFlags kann - ergo ist eine der drei Aussagen falsch:
- Window ist kein WindowFlags - die Vererbung passt nicht
- Window kann nach bool konvertiert werden - hattest du explizit verboten
- WindowFlags kann nicht nach bool konvertiert werden - ist auch nicht machbar, weil diese Umwandlung benötigt wird
Xin schrieb:
CStoll schrieb:
Xin schrieb:
Und ganz ehrlich, es gibt eine Grenze, da sichere ich nicht mehr ab. Ich baue keinen Zaun um einen großen Gastank, nur weil auf dem Tank jemand grillen könnte.
Darwin-Awards beweist, dass derartiges gemacht wird und das es tödliche Konsequenzen haben kann.
Ich finde den Kommentar "Kann Nüsse enthalten, bei Nussallergie nicht konsumieren" auf einer Packung Erdnüsse für lächerlich.Du bist ja auch kein Allergiker.
Doch. Ich bin allergisch gegen Roggen- und Graspollen. Ich vermeide zu gewissen Zeiten Grasflächen und Rasenmäher, obwohl da kein Schild steht "Für Grasallergiker zur Pollensaison nicht geeignet.". Da muss man mich nicht drauf hinweisen. Ich binde mir kein Startrakete auf's Autodach, nur weil da kein Aufkleber "nur als Starthilfe für Jets einsetzen" draufsteht.
Es gibt denkende Menschen und es gibt Menschen, die nicht denken. Und dann gibt es noch die Evolution und beides greift ineinander. Und das ist gut so...Ich hab' auch Heuschnupfen, meine Oma eine Allergie gegen Paprika (kein Problem, den kann man noch erkennen, bevor man ihn runterschluckt) etc. Aber irgendwo sind technische Grenzen dessen, was man noch mit gesundem Menschenverstand erkennen kann - und solange du nicht selber zugesehen hast, wie es hergestellt wurde, kannst du nicht sicher sein, ob dein Vollkornmüsli in der Nähe von Nüssen zwischengelagert wurde.
Xin schrieb:
Und nebenher: Wer gegen Operatoren-Überladung ist, muss zwangsläufig auch gegen Funktionsüberladung sein, denn nichts anderes ist die operator-Überladung.
Ja zurück zu den Wurzeln - schreiben wir wieder in C
-
CStoll schrieb:
Xin schrieb:
CStoll schrieb:
Wir sind immer noch bei der alten Frage: Setze ich mit "wnd=Window::Modal;" nun das Fullscreen-Flag zurück oder nicht?
Hatte ich das nicht schon mehrfach als No-Go-Befehl geoutet, den ich für Dich extra als private setzte?
Ergo setzt wnd=Winodw::Modal den Compiler zurück und der dankt es mit einer Fehlermeldung.Was denn nun - auf der einen Seite bietest du einen operator= mit der Semantik "setze alle Flags zurück und stelle dann Flag xyz ein", auf der anderen Seite erklärst du mir, daß es keinen solchen Operator gibt. Entscheide dich bitte.
Für Dich gibt's keinen, weil Du das böse findest. Ich brauche nicht unbedingt einen.
CStoll schrieb:
Xin schrieb:
CStoll schrieb:
Aber aus OOP-Sicht ist die Vererbung von Farbe->Auto trotzdem Käse. (und um ein Auto an eine farbverarbeitende Funktion zu übergeben, ist eine Typumwandlung über 'operator Farbe()' besser geeignet).
Behauptung. Begründung?
Hast du schonmal versucht, dein Haus mit einem Auto zu lackieren? Wenn ja, was ist dabei herausgekommen?
Es gibt Menschen, für die gilt:
Ferrari = Farbe( Handtaeschchen );Nichtsdestotrotz wird der Ferrari dann vom Operator nicht eingefärbt, sondern lackiert. Die Information Farbe enthält schließlich nicht die Färbungsvorschrift.
Also hat die Frage irgendwas mit dem Problem zu tun? Die Postings werden zu lang, sowas kannst Du also in Zukunft auch weglassen.CStoll schrieb:
Wo du ständig auf Kürze rumreitest - was ist der Unterschied zwischen "c = VCurrent(v);" und "c.VCurrent = v;"? Ich finde jedenfalls letzeres klarer.
Hehehe, ich habe die Lösung, die mehr mehr Schreibarbeit bedeutet und jetzt behauptest Du, ich reite ständig auf der Kürze herrum?
Die Verkürzung im Algorithmus ist ein sehr guter Vorteil, ob das den Mehraufwand rausholt, weiß ich nicht. Also wird die "Kürze" allgemein nicht der alleinige Grund sein - den Hauptgrund hast Du ja bereits gesehen.CStoll schrieb:
Xin schrieb:
Nur für den Fall, dass Du es nicht gesehen hast: Die Sitze in einem Auto beschreiben wunderbar genau das, was ich als Member ("besteht-aus") beschreiben würde, denn ein Auto verhält sich nicht wie ein Sitz und ist auch kein Sitz.
Ein Auto verhält sich auch nicht wie eine Geschwindigkeit (kann die sich überhaupt verhalten?) - ein Auto hat eine Geschwindigkeit. (ja, die Beziehung Auto<->Geschwindigkeit ist etwas technisch anderes als Auto<->Sitz oder Auto<->Motor, aber sie liegt definitiv näher an "hat-ein" als an "ist-ein")
Hey, CStoll, das wird ja richtig philosophisch.
Okay, spielen wir mal mit.
Eine Geschwindigkeit ist etwas nichts Greifbares, also kann man Geschwindigkeit nicht besitzen, also auch nicht haben. Für Member verwendet man auch gerne die Beziehung "besteht aus" passt hier auch nicht, denn ein Auto besteht aus keinem Stück Geschwindigkeit.
Ein Auto ist mit einer Geschwindigkeit unterwegs.
Ein Auto ist schnell.Geschwindigkeit ist ein Zustand.
Ein Fenster ist ein Zustand. Und wenn man Dialog von Fenster ableitet, so erbt ein Objekt Dialog auch den Zustand Fenster.
Zustände kann man haben, aber auch vererben. Das ist eine Designentscheidung. Man kann einen Dialog auch mit einer "besteht-aus"-Beziehung realisieren.
Ich sehe keinen Grund, warum man einen Geschwindkeitszustand nicht erben könnte.
So könnte man zum Beispiel Physikalische Eigenschaften verbinden und Gegenstände wie Autos und Äpfel mit Masse und Geschwindigkeit, Positionen und Ausmaßen ausstatten und gucken was passiert, wenn sich Autos gegen rollende Äpfel prallen, ohne Autos oder Äpfel zu verändern.
Das geht bei Membern genausowenig, wie bei schlechten Beziehungen zwischen Klassen.CStoll schrieb:
Xin schrieb:
Die Tatsache, dass sich das alles mit Membervariablen lösen lässt, bedeutet nicht, dass diese Methode schlecht wäre. Dieser Sourcecode beschreibt nichts anderes als den Zugriff auf Membervariablen.
Und was hast du davon? Kiloweise Hilfsklassen, die nichts anderes machen, als 'int' einen neuen Namen zu geben. In der Anwendung ist sowas bestenfalls gewöhnungsbedürftig - und schlimmstenfalls füllst du dir den globalen Namensraum mit Bezeichnern, die nur in Zusammenwirken mit deinen Klassen eine Bedeutung haben.
Und die vor allem ein int genau klassifizieren. Eine Funktion, die eine Strecke erwartet, kann nicht mehr mit einer Fläche gefüttert werden. Das dafür viele Klassen erforderlich sind, schmällert den Mehrwert nicht, schließlich ist der Sinn von Klassen, Datensätze zu klassifizieren, selbst wenn sie nur aus einem int bestehen.
CStoll schrieb:
Xin schrieb:
Man sollte Vererbung nicht nur als eine "ist-ein" betrachten, sondern auch sehen, dass hier eigenständige Eigenschaften zusammengebracht werden können, die eine Klasse ausmachen.
Vererbung in C++ stellt nunmal eine "ist-ein"-Beziehung dar - auch wenn du dich auf den Kopf stellst, mußt du andere Anwendungen erst einmal begründen.
Das habe ich hier begründet: Gleiche Eigenschaften haben in den Klassen auch zwangsläufig gleiche Namen, weil sie über die Klasse und nicht über ein beliebig zu nennendes Member angesprochen werden.
Und warum sollte ich mich da noch weiter in der Beweispflicht fühlen?
Du begründest ja auch nicht, warum Du davon ausgehst, dass Vererbung ausschließlich "ist-ein" bedeuten darf. Hast Du das "ausschließlich" mal in einem Buch gelesen? Hat der Autor das "ausschließlich" begründet? Und war der Grund erwähnenswert?
CStoll schrieb:
Xin schrieb:
Das einzige, was für mich zählt ist, wie man mit den Klassen umgehen kann, wenn sie erstmal implementiert sind.
Notfalls packe ich Dir sämtliche Flags nochmals als private in die Windowklasse, da habe ich kein Problem mit. Mir ist wichtig, dass ich garantieren kann, dass Eigenschaften zwangsläufig immer den gleichen Namen haben. Den Namen einer Eigenschaftsklasse kann ich nicht von Klasse zu Klasse ändern, den Namen einer Membervariablen schon. Das über ein Framework immer konstant zu halten, ist eine Sache, die viel mehr Disziplin verlangt, als derartige Klassen einmalig sehr ausführlich beschreiben zu müssen.Die Namen der öffentlichen Schnittstelle werden auch in der Hierarchie durchgereicht, also wo siehst du das Problem?
Ich habe keinen Bock in die Doku zu gucken. Kenne ich die Klassen, habe ich alles, was ich brauche, um an die Daten zu kommen, die mich interessieren.
CStoll schrieb:
Xin schrieb:
CStoll schrieb:
Und damit sind wir doch wieder bei der Rechteck-Quadrat-Problematik angekommen: Du sagst: "ein Fenster ist ein Flag", "ein Flag kann nach bool konvertiert werden" und "ein Fenster kann nicht nach bool konvertiert werden" - siehst du den Widerspruch in diesen Aussagen?
Ich sagte ein Window ist eine Erweiterung zu WindowFlags und kann zu WindowFlags konvertiert werden.
Den operator bool habe ich auf Deinen Wunsch für Deppenprogrammierer jetzt private gesetzt, weil ich zustimme, dass ein Fenster kein bool ist.
Auch wenn Du es noch 10mal wiederholst, noch privater kann ich's nicht setzen. Das Problem, welches keins sein darf, weil kein denkender Entwicker diese Frage stellen darf, ist selbst für die nicht denkenden gelöst. Darauf rumzureiten, bringt uns also nicht weiter. Es ist punktuell gelöst und muss nie wieder gelöst werden.Ja, das Problem hast du gelöst, aber damit die "ist-ein"-Beziehung zwischen WindowFlags und Window ausgehebelt. Wenn Window ein WindowFlags ist, muß es auch alles können, was ein WindowFlags kann - ergo ist eine der drei Aussagen falsch:
- Window ist kein WindowFlags - die Vererbung passt nicht
- Window kann nach bool konvertiert werden - hattest du explizit verboten
- WindowFlags kann nicht nach bool konvertiert werden - ist auch nicht machbar, weil diese Umwandlung benötigt wird
Ich hab's für Dich verboten, bei mir ist es nicht verboten. Bei mir darf man auch idiotische Fragen stellen. Macht aber keiner. Also ein Window ist ein WindowFlag und ein Window erlaubt bei mir alles, was ein WindowFlag erlaubt.
Wenn ich diese Sachen verbiete, habe ich das auch kein Problem mit, denn Du sagst, dass ausschließlich die "ist-ein"-Beziehung der wahre Glaube ist. Ich frage nach dem Nutzen einer Beziehung und beschreibe die Beziehung so, dass sie mir nützt.
Ich kann also vieles, was ich geerbt habe auch Private setzen, dann ist ein Window kein WindowFlag mehr, aber das ist für die Beziehung auch nicht erforderlich.
Ich kann auch WindowFlag und WindowFlags trennen und Window nur von WindowFlags ableiten, die Operatoren global definieren und alle sind glücklich - inkl. Compiler - das ist die perfekte Lösung.
Das ist mir allerdings zu aufwendig, nur damit irgendwelche Flags nicht im Namensraum von Window auftreten und man eine Frage nicht stellen kann, die ein intelligenter Entwickler niemals stellen würde. Das bringt mir zuwenig nutzen, um es umzusetzen und darum gehe ich den einfacheren Weg, der einige Risiken von "int Flags" nicht beseitigt bei den Algorithmen allerdings den Code - subjektiv empfunden - vereinfacht und der mehr Typsicherheit bietet.CStoll schrieb:
Ich hab' auch Heuschnupfen, meine Oma eine Allergie gegen Paprika (kein Problem, den kann man noch erkennen, bevor man ihn runterschluckt) etc. Aber irgendwo sind technische Grenzen dessen, was man noch mit gesundem Menschenverstand erkennen kann - und solange du nicht selber zugesehen hast, wie es hergestellt wurde, kannst du nicht sicher sein, ob dein Vollkornmüsli in der Nähe von Nüssen zwischengelagert wurde.
Und wenn Du als Nussallergiker eine Packung Nüsse kaufst, dann hast Du Probleme zu erkennen, dass da Nüsse drin sein könnten?
Hier geht es um Dokumentationsnotwendigkeit - wieviel Verstand darf man einem Entwickler zutrauen. Ob im Detail ein Vollkornmüsli in der Nähe von Nüssen geparkt wird, spielt bei einer Designentscheidung keine Rolle, da würde man das als Designfehler bezeichnen. Hier stellt sich die Frage, ob Du als Nussallergiker darauf hingewiesen werden musst, dass Nüsse Nüsse enthalten werden können. Wer ohne Schulung nicht verstehen kann, dass er keine Nüsse verträgt und deswegen keine Nüsse essen darf, der sollte nicht entwickeln.
CStoll schrieb:
Xin schrieb:
Und nebenher: Wer gegen Operatoren-Überladung ist, muss zwangsläufig auch gegen Funktionsüberladung sein, denn nichts anderes ist die operator-Überladung.
Ja zurück zu den Wurzeln - schreiben wir wieder in C
Das war exakt mein Gedanke, als ich Shades Posting las...
-
Operatoren Überladung ist nicht gleich Funktionsüberladung da Operatoren vordefinierte Bedeutungen haben.
Ein operator+ ist zB eine Funktion addXXX() - und meine Kritik ist, dass hier Operatoren für etwas eingesetzt werden was nicht der mathematischen auffassung entspricht. Ähnlich wie << als ausgabe-operator.
Meine kritik also ist, dass ein
car+=10;
einem
car.add(10);
entspricht und das unlogisch ist. man braucht ein increaseSpeed oder sonst etwas dass auf die geschwindigkeit hinweist, da man sonst den leser des codes verwirrt.
-
Xin schrieb:
Ich finde den Kommentar "Kann Nüsse enthalten, bei Nussallergie nicht konsumieren" auf einer Packung Erdnüsse für lächerlich.
Wieder mal glaubst Du Dich im Besitz der absoluten Wahrheit. Anstatt einfach mal die Möglichkeit zu überdenken, daß Nüsse im Sinne dieses Hinweises etwas anderes sind als das, was Du Dir unter Nüssen vorstellst.
Zu Deinem restlichen Unfug braucht man schon nix mehr zu sagen. Fenster sind keine Flags, sondern haben (vielleicht) welche.
Ansonsten erklär einfach mal, was Deiner Meinung nach ein Flag ist. Ich bin an Deiner Meinung interessiert, jedoch nicht an Ablenkungsmanövern.
-
Xin schrieb:
CStoll schrieb:
Xin schrieb:
Nur für den Fall, dass Du es nicht gesehen hast: Die Sitze in einem Auto beschreiben wunderbar genau das, was ich als Member ("besteht-aus") beschreiben würde, denn ein Auto verhält sich nicht wie ein Sitz und ist auch kein Sitz.
Ein Auto verhält sich auch nicht wie eine Geschwindigkeit (kann die sich überhaupt verhalten?) - ein Auto hat eine Geschwindigkeit. (ja, die Beziehung Auto<->Geschwindigkeit ist etwas technisch anderes als Auto<->Sitz oder Auto<->Motor, aber sie liegt definitiv näher an "hat-ein" als an "ist-ein")
Hey, CStoll, das wird ja richtig philosophisch.
Okay, spielen wir mal mit.
Eine Geschwindigkeit ist etwas nichts Greifbares, also kann man Geschwindigkeit nicht besitzen, also auch nicht haben. Für Member verwendet man auch gerne die Beziehung "besteht aus" passt hier auch nicht, denn ein Auto besteht aus keinem Stück Geschwindigkeit.
Ein Auto ist mit einer Geschwindigkeit unterwegs.
Ein Auto ist schnell.Geschwindigkeit ist ein Zustand.
Ein Fenster ist ein Zustand. Und wenn man Dialog von Fenster ableitet, so erbt ein Objekt Dialog auch den Zustand Fenster.Ein Fenster ist kein Zustand, sondern ein (mehr oder weniger) real existierendes Objekt. Ein Dialog ist eine spezielle Art von Fenster.
Und ja, für Zustände gibt es in C++ kein eigenes Sprachmittel (du hast deine Typerweiterungen für sowas entwickelt(?)).
Xin schrieb:
CStoll schrieb:
Xin schrieb:
Die Tatsache, dass sich das alles mit Membervariablen lösen lässt, bedeutet nicht, dass diese Methode schlecht wäre. Dieser Sourcecode beschreibt nichts anderes als den Zugriff auf Membervariablen.
Und was hast du davon? Kiloweise Hilfsklassen, die nichts anderes machen, als 'int' einen neuen Namen zu geben. In der Anwendung ist sowas bestenfalls gewöhnungsbedürftig - und schlimmstenfalls füllst du dir den globalen Namensraum mit Bezeichnern, die nur in Zusammenwirken mit deinen Klassen eine Bedeutung haben.
Und die vor allem ein int genau klassifizieren. Eine Funktion, die eine Strecke erwartet, kann nicht mehr mit einer Fläche gefüttert werden. Das dafür viele Klassen erforderlich sind, schmällert den Mehrwert nicht, schließlich ist der Sinn von Klassen, Datensätze zu klassifizieren, selbst wenn sie nur aus einem int bestehen.
Wenn du einen int mit einer Maßeinheit versehen willst, um Strecken und Gewichte unterscheiden zu können, geht das in die richtige Richtung. Aber Hilfsklassen anlegen zu müssen, nur um einer Area zwei Maßzahlen übergeben zu können halte ich ein wenig übertrieben. Und außerdem tendiert der Ansatz auf Dauer zu extrem langen Variablennamen (gerade wenn ich mehrere technisch ähnliche Klassen an verschiedenen Stellen des Programms verwenden will).
Achja: Wie willst du auf diese Weise einen Bildfilter (hat zwei Bildbereiche und überträgt Daten von einem zum anderen) mit der DigiCam-Klasse zusammenarbeiten lassen - oder ein Polygon (besteht aus einer variablen Anzahl an Punkten) in dein Design einbauen?
Xin schrieb:
CStoll schrieb:
Xin schrieb:
Man sollte Vererbung nicht nur als eine "ist-ein" betrachten, sondern auch sehen, dass hier eigenständige Eigenschaften zusammengebracht werden können, die eine Klasse ausmachen.
Vererbung in C++ stellt nunmal eine "ist-ein"-Beziehung dar - auch wenn du dich auf den Kopf stellst, mußt du andere Anwendungen erst einmal begründen.
Das habe ich hier begründet: Gleiche Eigenschaften haben in den Klassen auch zwangsläufig gleiche Namen, weil sie über die Klasse und nicht über ein beliebig zu nennendes Member angesprochen werden.
Und im Ernstfall muß man die Eigenschaften dann doch wieder duplizieren - und hat neue Namen.
Xin schrieb:
Und warum sollte ich mich da noch weiter in der Beweispflicht fühlen?
Du begründest ja auch nicht, warum Du davon ausgehst, dass Vererbung ausschließlich "ist-ein" bedeuten darf. Hast Du das "ausschließlich" mal in einem Buch gelesen? Hat der Autor das "ausschließlich" begründet? Und war der Grund erwähnenswert?
Die Begründung dürfte zu lang werden, um sie hier zu posten - du kannst sie aber gerne selber nachlesen:
Effektiv C++ programmieren | ISBN: 9783827313058Xin schrieb:
CStoll schrieb:
Xin schrieb:
Das einzige, was für mich zählt ist, wie man mit den Klassen umgehen kann, wenn sie erstmal implementiert sind.
Notfalls packe ich Dir sämtliche Flags nochmals als private in die Windowklasse, da habe ich kein Problem mit. Mir ist wichtig, dass ich garantieren kann, dass Eigenschaften zwangsläufig immer den gleichen Namen haben. Den Namen einer Eigenschaftsklasse kann ich nicht von Klasse zu Klasse ändern, den Namen einer Membervariablen schon. Das über ein Framework immer konstant zu halten, ist eine Sache, die viel mehr Disziplin verlangt, als derartige Klassen einmalig sehr ausführlich beschreiben zu müssen.Die Namen der öffentlichen Schnittstelle werden auch in der Hierarchie durchgereicht, also wo siehst du das Problem?
Ich habe keinen Bock in die Doku zu gucken. Kenne ich die Klassen, habe ich alles, was ich brauche, um an die Daten zu kommen, die mich interessieren.
Du hast die Klassen geschrieben, also verstehst du auch das dahinterliegende Konzept. Andere Programmierer müssen erstmal das Konzept verstanden haben, bevor sie überhaupt daran gehen können, deine Zustands-Klassen einsetzen zu können.
(und wie du inzwischen bemerkt haben dürftest, widerspricht dein Konzept zumindest der "üblichen" Vorgehensweise)Xin schrieb:
CStoll schrieb:
Xin schrieb:
CStoll schrieb:
Und damit sind wir doch wieder bei der Rechteck-Quadrat-Problematik angekommen: Du sagst: "ein Fenster ist ein Flag", "ein Flag kann nach bool konvertiert werden" und "ein Fenster kann nicht nach bool konvertiert werden" - siehst du den Widerspruch in diesen Aussagen?
Ich sagte ein Window ist eine Erweiterung zu WindowFlags und kann zu WindowFlags konvertiert werden.
Den operator bool habe ich auf Deinen Wunsch für Deppenprogrammierer jetzt private gesetzt, weil ich zustimme, dass ein Fenster kein bool ist.
Auch wenn Du es noch 10mal wiederholst, noch privater kann ich's nicht setzen. Das Problem, welches keins sein darf, weil kein denkender Entwicker diese Frage stellen darf, ist selbst für die nicht denkenden gelöst. Darauf rumzureiten, bringt uns also nicht weiter. Es ist punktuell gelöst und muss nie wieder gelöst werden.Ja, das Problem hast du gelöst, aber damit die "ist-ein"-Beziehung zwischen WindowFlags und Window ausgehebelt. Wenn Window ein WindowFlags ist, muß es auch alles können, was ein WindowFlags kann - ergo ist eine der drei Aussagen falsch:
- Window ist kein WindowFlags - die Vererbung passt nicht
- Window kann nach bool konvertiert werden - hattest du explizit verboten
- WindowFlags kann nicht nach bool konvertiert werden - ist auch nicht machbar, weil diese Umwandlung benötigt wird
Ich hab's für Dich verboten, bei mir ist es nicht verboten. Bei mir darf man auch idiotische Fragen stellen. Macht aber keiner. Also ein Window ist ein WindowFlag und ein Window erlaubt bei mir alles, was ein WindowFlag erlaubt.
So viel Disziplin - echt erstaunlich
Randfrage: Wieviele Leute arbeiten bisher mit deinem Framework?Xin schrieb:
Wenn ich diese Sachen verbiete, habe ich das auch kein Problem mit, denn Du sagst, dass ausschließlich die "ist-ein"-Beziehung der wahre Glaube ist. Ich frage nach dem Nutzen einer Beziehung und beschreibe die Beziehung so, dass sie mir nützt.
Ich kann also vieles, was ich geerbt habe auch Private setzen, dann ist ein Window kein WindowFlag mehr, aber das ist für die Beziehung auch nicht erforderlich.
Ich kann auch WindowFlag und WindowFlags trennen und Window nur von WindowFlags ableiten, die Operatoren global definieren und alle sind glücklich - inkl. Compiler - das ist die perfekte Lösung.Oder du vererbst gleich privat und redefinierst die notwendigen Operatoren in der Window-Klasse.
Xin schrieb:
CStoll schrieb:
Ich hab' auch Heuschnupfen, meine Oma eine Allergie gegen Paprika (kein Problem, den kann man noch erkennen, bevor man ihn runterschluckt) etc. Aber irgendwo sind technische Grenzen dessen, was man noch mit gesundem Menschenverstand erkennen kann - und solange du nicht selber zugesehen hast, wie es hergestellt wurde, kannst du nicht sicher sein, ob dein Vollkornmüsli in der Nähe von Nüssen zwischengelagert wurde.
Und wenn Du als Nussallergiker eine Packung Nüsse kaufst, dann hast Du Probleme zu erkennen, dass da Nüsse drin sein könnten?
Hier geht es um Dokumentationsnotwendigkeit - wieviel Verstand darf man einem Entwickler zutrauen. Ob im Detail ein Vollkornmüsli in der Nähe von Nüssen geparkt wird, spielt bei einer Designentscheidung keine Rolle, da würde man das als Designfehler bezeichnen. Hier stellt sich die Frage, ob Du als Nussallergiker darauf hingewiesen werden musst, dass Nüsse Nüsse enthalten werden können. Wer ohne Schulung nicht verstehen kann, dass er keine Nüsse verträgt und deswegen keine Nüsse essen darf, der sollte nicht entwickeln.
Bei einer Packung Erdnüsse ist klar, daß sie Nüsse enthalten wird - bei einer Packung Vollkornmüsli ist nicht sicher, ob vielleicht doch Spuren von Nüssen hineingekommen sein können (und mitunter reichen diese Spuren schon aus, um lebensgefährlich zu werden). (edit: Zum Nachlesen - Allergie)
Genauso: Bei der Verwendung "wnd.Flags|=Fullscreen;" oder "wnd.SetFlag(Fullscreen);" wird deutlich, daß ich einen Teilaspekt meiner Klasse ändere, bei "wnd|=Window::Fullscreen;" sieht man auf den ersten Blick zu eine Zuweisung und muß erstmal verstehen/nachsehen, was sie machen soll.1
-
CStoll schrieb:
Xin schrieb:
CStoll schrieb:
Xin schrieb:
Nur für den Fall, dass Du es nicht gesehen hast: Die Sitze in einem Auto beschreiben wunderbar genau das, was ich als Member ("besteht-aus") beschreiben würde, denn ein Auto verhält sich nicht wie ein Sitz und ist auch kein Sitz.
Ein Auto verhält sich auch nicht wie eine Geschwindigkeit (kann die sich überhaupt verhalten?) - ein Auto hat eine Geschwindigkeit. (ja, die Beziehung Auto<->Geschwindigkeit ist etwas technisch anderes als Auto<->Sitz oder Auto<->Motor, aber sie liegt definitiv näher an "hat-ein" als an "ist-ein")
Hey, CStoll, das wird ja richtig philosophisch.
Okay, spielen wir mal mit.
Eine Geschwindigkeit ist etwas nichts Greifbares, also kann man Geschwindigkeit nicht besitzen, also auch nicht haben. Für Member verwendet man auch gerne die Beziehung "besteht aus" passt hier auch nicht, denn ein Auto besteht aus keinem Stück Geschwindigkeit.
Ein Auto ist mit einer Geschwindigkeit unterwegs.
Ein Auto ist schnell.Geschwindigkeit ist ein Zustand.
Ein Fenster ist ein Zustand. Und wenn man Dialog von Fenster ableitet, so erbt ein Objekt Dialog auch den Zustand Fenster.Ein Fenster ist kein Zustand, sondern ein (mehr oder weniger) real existierendes Objekt. Ein Dialog ist eine spezielle Art von Fenster.
Und ja, für Zustände gibt es in C++ kein eigenes Sprachmittel (du hast deine Typerweiterungen für sowas entwickelt(?)).
Alles ist ein Objekt? Da muss ich einfach an Stepanov denken:
I find OOP technically unsound. It attempts to decompose the world in terms of interfaces that vary on a single type. To deal with the real problems you need multisorted algebras - families of interfaces that span multiple types. I find OOP philosophically unsound. It claims that everything is an object. Even if it is true it is not very interesting - saying that everything is an object is saying nothing at all. I find OOP methodologically wrong. It starts with classes. It is as if mathematicians would start with axioms. You do not start with axioms - you start with proofs. Only when you have found a bunch of related proofs, can you come up with axioms. You end with axioms. The same thing is true in programming: you have to start with interesting algorithms. Only when you understand them well, can you come up with an interface that will let them work.
naja, das war jetzt OT - keine Stellungnahme zum Thema selbst.