Als Java-Entwickler noch C/C++ dazulernen: Chancenlos?
-
Ich bin heute absolut überzeugt, dass die Mehrfachvererbung wieder kommt. Dafür steckt viel zuviel Potential darin, Boilerplate zu sparen und den Entwickler dazu zu nötigen, sich eindeutig auszudrücken. Ein vollkommen unterschätztes Konzept.
Aber sicher nicht wie C++ das macht.
Sondern eher mit traits ala Scala.
-
Xin schrieb:
ich spielte durchaus schon mit dem Gedanken, Aggregationen komplett abzuschaffen: weniger Boilerplate und zwangsläufig scharfe Typdefinitionen. Das will man doch!?
Wenn ich richtig verstanden habe, wie du Vererbung einsetzt, koppelst du aber auch stärker. Stichwort als Beispiel: Inversion of Control.
Außerdem kannst du Kapselung schwieriger steuern, bei Aggregation mit Komponente K kannst du die Implementierung für Aggregationspartner leicht verstecken und dabei für Subklassen von K immernoch gewisse Teile des Zustands zugreifbar machen [protected].
-
marco.b schrieb:
Xin schrieb:
ich spielte durchaus schon mit dem Gedanken, Aggregationen komplett abzuschaffen: weniger Boilerplate und zwangsläufig scharfe Typdefinitionen. Das will man doch!?
Wenn ich richtig verstanden habe, wie du Vererbung einsetzt, koppelst du aber auch stärker. Stichwort als Beispiel: Inversion of Control.
Wieso kopple ich stärker? Wenn ich beschreibe, dass ein Kleiderbügel ein Ausführung eines Hakens mit Kleiderhalter ist und eine Ausführung von Kleiderhalter ist - oder ob ein Kleiderbügel aus einen Haken und einem Kleiderhalter besteht, so habe ich so oder so einen Kleiderbügel.
Das hat keinen Einfluss darauf, wie die der Haken mit der Kleiderstange kommuniziert oder der Kleiderhalter mit der Kleidung!?
Oder verstehe ich Deinen Punkt hier gerade nicht korrekt?
marco.b schrieb:
Außerdem kannst du Kapselung schwieriger steuern, bei Aggregation mit Komponente K kannst du die Implementierung für Aggregationspartner leicht verstecken und dabei für Subklassen von K immernoch gewisse Teile des Zustands zugreifbar machen [protected].
Wie gesagt, ich habe auch kein Problem mit Aggregationen, ich nutze die Mehrfachvererbung nur gerne, als öffentliche Aggregation mit vereinfachtem Zugriff. Vererbung ist nichts anderes als Aggregation.
Man schreibt seine Klassen entsprechend so, dass man gut von ihnen ableiten kann und arbeitet wie mit Lego.
Finde ich sehr praktisch, spart Code und das ist in meinen Augen auch semantisch zu vertreten, denn "besteht aus" und "ist ein" ist häufig nur die Frage, wie man sich der Sache nähert.Die Farbe eines Autos, ist ein öffentliches Attribut. Mein Auto ist keine Farbe. Trotzdem ist mein Auto blau (myCar == Color::Blue;). Ich kann auch sagen, die Farbe von meinem Auto ist blau (myCar.Color == Color::Blue;). Die Frage ist schlussendlich, wieviel Kontext brauchst Du?
Bei einer Funktion Color::Mix( yourCar, myCar ) muss man selbst wissen, ob man erwähnen muss, dass man die Farbe meint? Wenn das undurchschaubar ist, geht das über Aggregation natürlich deutlicher: Color::Mix( yourCar.Color, myCar.Color )Dein Punkt ist absolut korrekt, wenn es darum geht, Daten zu schützen, zum Beispiel das FileHandle in einer class File.
Allerdings interessieren sich Funktionen, die z.B. nur mit einem PowerSupply arbeiten nicht dafür, was das reingereichte Objekt denn noch so alles kann. Ich sehe nicht, was ich hier verstecken müsste, vielleicht ein BluRay-Player, vielleicht ein Fernseher, egal... ich frage nur, wieviel Strom das Ding verbraucht: ganz öffentliche Funktion.
Ich halte Mehrfachvererbung für ein sehr praktisches Mittel, Quellcodes kurz zu halten und mache reichlich Gebrauch davon und kann das Dogma, dass Mehrfachvererbung Werk des Teufels wäre, absolut nicht nachvollziehen.
-
Xin schrieb:
Ich gucke Filme auf BluRay-FullHD-Kombi-Gerätes - fertig. Du schaust dann halt auf dem Display, dass Du per Getter aus dem FullHDFernsehers geholt hast, den Du per Getter aus dem BluRay-FullHD-Kombi-Gerätes geholt hast. Interessiert mich das?
Ich finde die ganze Klassenhierachie eh unglücklich, aber um mal bei dem Beispiel zu bleiben:
Wie implementierst du denn allgemeine Funktionen, die auf der Basisklasse arbeiten? Sowas wiebool canPlayBlueRay(Display* display)
Mit dynamic_cast?
-
Jockelx schrieb:
Xin schrieb:
Ich gucke Filme auf BluRay-FullHD-Kombi-Gerätes - fertig. Du schaust dann halt auf dem Display, dass Du per Getter aus dem FullHDFernsehers geholt hast, den Du per Getter aus dem BluRay-FullHD-Kombi-Gerätes geholt hast. Interessiert mich das?
Ich finde die ganze Klassenhierachie eh unglücklich, aber um mal bei dem Beispiel zu bleiben:
Wie implementierst du denn allgemeine Funktionen, die auf der Basisklasse arbeiten? Sowas wiebool canPlayBlueRay(Display* display)
Mit dynamic_cast?
Gar nicht. Die Frage hat auch nix mit Mehrfachvererbung zu tun.
Ein Display kann keine Blurays abspielen. Darum ist es ein Display. Das Display selbst hat auch keine Verwandtschaft mit einem BluRayPlayer. Die Antwort wäre also grundsätzlich 'false'. Wenn ich die Antwort kenne, ist die Frage überflüssig.
Eine Funktion, die auf der Basisklasse arbeitet und sich für BluRay-Funktionalität interessiert würde als Parameter einen BluRayPlayer erwarten und der würde "bool canPlayBlueRay(BluRayPlayer * player)" grundsätzlich true antworten und - hatten wir ja schon: Wenn ich die Antwort kenne, ist die Frage überflüssig.
Was immer ich mit canPlayBlueRay() reinstecken kann - sagen wir mal this - ist von irgendeinem Typen, der mindestens von Display geerbt hat.
Deine Frage wäre mit dynamic_cast zu beantworten, aber nicht schön zu lesen.
Wenn ich diese Frage also stellen möchte, dann muss ich mich (also this) fragen, ob ich BluRays abspielen kann.Beispiel aus meiner Praxis: Ich programmiere eine eigene Programmiersprache, dort gibt es Operatoren (z.B. Addition oder Negierung). Hier stellt sich zum Beispiel unter Umständen die Frage, ob das ein binärer Operator ist.
Die Vererbungs Hierarchie ist dann Operator->PriorityOperator->BinaryOperator->Addition
Operator definiert die Frage virtual bool IsBinary() const { return false; }, BinaryOperator überschreibt die Funktion mit { return true; }.Wenn Du das nicht von Hand ändern möchtest, dann wäre der dynamic_cast das Mittel der Wahl - würde aber zur Laufzeit mehr Zeit in Anspruch nehmen.
bool IsBinary() const { return nullptr != dynamic< BinaryOperator const * >( this ); }
Aber wie gesagt - das ist eine gerade Vererbungslinie: Das hat nichts mit Displays zu tun oder Mehrfachvererbung zu tun.
Du müsstest Du dem Display die Fragemöglichkeit mitgeben, ob es BluRays abspielen kann und diese Information - vollkommen unabhängig von der Mehrfachvererbung an der Stelle ändern, wo Du per Mehrfachvererbung den BlurayPlayer dazupackst.
In dem Fall musst Du ohne Mehrfachvererbung sogar auf die return true/false-Lösung ausweichen, da Du zur Laufzeit nicht mehr prüfen kannst, ob Deine Instanz eine Aggregation BluRayPlayer besitzt und selbst dann wäre das übergebene Display nur das Display und Du hättest mit dem (Display *)-Datentyp keine Chance mehr an den BluRay-Player ran zu kommen, der eventuell in dem Objekt sitzt, in dem das Display als Member enthalten ist.Entsprechend wirst Du Deine Funktionen so formulieren, dass Du diese Probleme gar nicht hast, womit wir wieder bei der ersten Antwort auf Deine Frage sind: Eine Frage wie "bool canPlayBlueRay(Display* display)" muss ich nicht implementieren und wenn doch habe ich etwas verkehrt gemacht, was nichts mit Mehrfachvererbung zu tun.
Hier holst Du Dir über dynamic_cast nur die Möglichkeit rein, eine Frage, zu beantworten, die Du Dir hoffentlich gar nicht stellen musst.
-
Was genau ist der Sinn davon, ein Document von Filename erben zu lassen!?
Xin schrieb:
Beispiel aus meiner Praxis: Ich programmiere eine eigene Programmiersprache, dort gibt es Operatoren (z.B. Addition oder Negierung). Hier stellt sich zum Beispiel unter Umständen die Frage, ob das ein binärer Operator ist.
Was hat die Basisklasse Operator für einen Sinn, wenn du später dann solche Fragen stellst?
Xin schrieb:
Vererbung ist nichts anderes als Aggregation.
Wieso kann ich ein Objekt von abgeleitetem Typ dann wie ein Objekt vom Typ der Basisklasse behandeln? Das widerspricht doch dem Grundgedanken von Aggregation!?
-
dot schrieb:
Was genau ist der Sinn davon, ein Dokument von Filename erben zu lassen!?
Das ist so nie geschrieben worden.
BitmapDocument erbte von Document, Filename und Bitmap.
Es ist auch nur ein Beispiel. Ich habe zwar die jeweiligen Klassen, aber afair keine Klasse BitmapDocument. Was ich damit fabriziert habe, hätte einen eigenen Artikel zur Erklärung benötigt, also habe ich das nur flott auf BitmapDocument runtergebrochen.
PS: Und der Rest:
dot schrieb:
Xin schrieb:
Beispiel aus meiner Praxis: Ich programmiere eine eigene Programmiersprache, dort gibt es Operatoren (z.B. Addition oder Negierung). Hier stellt sich zum Beispiel unter Umständen die Frage, ob das ein binärer Operator ist.
Was hat die Basisklasse Operator für einen Sinn, wenn du später dann solche Fragen stellst?
Funktionalität hochziehen, die nicht in den einzelnen Operatoren ausgeführt werden muss. Die Frage stellt sich, wenn ein Algorithmus in class Operator für eine bestimmte Sorte von Operatoren anders funktioniert, wenn es ich um einen Binären Operator handelt.
dot schrieb:
Xin schrieb:
Vererbung ist nichts anderes als Aggregation.
Wieso kann ich ein Objekt von abgeleitetem Typ dann wie ein Objekt vom Typ der Basisklasse behandeln? Das widerspricht doch dem Grundgedanken von Aggregation!?
Das hängt sehr stark davon ab, was Du unter Aggregation verstehst.
Aggregation ist eine "Haufen von Zeugs" und sagt nix darüber wer hier welche Rechte hat.
Bei:
struct A { int a; }; struct B : public A { int b; } bi; struct C { A a; int b; } ci;
unterscheiden sich class B und class C überhaupt nicht. Du darfst die Instanz bi überall da reinwerfen, wo Du A reinwerfen darfst und bei C musst Du halt ci.a schreiben.
Am Programm ändert das nichts - es stellt sich nur die Frage, ob Du das betonen möchtest oder nicht.
Eine Aggregation ist beides: die Anhäufung der beiden Membern a und b, jeweils 4 Byte groß. Du kannst lustig hin- und hercasten. Knorr oder Maggie - alles Tütensuppe.
-
Xin schrieb:
dot schrieb:
Was genau ist der Sinn davon, ein Dokument von Filename erben zu lassen!?
Das ist so nie geschrieben worden.
BitmapDocument erbte von Document, Filename und Bitmap.
Erklär mir bitte, wie das sein kann, dass ein BitmapDocument, das von Document, Filename und Bitmap erbt, nicht von Filename erbt!?
Xin schrieb:
dot schrieb:
Xin schrieb:
Beispiel aus meiner Praxis: Ich programmiere eine eigene Programmiersprache, dort gibt es Operatoren (z.B. Addition oder Negierung). Hier stellt sich zum Beispiel unter Umständen die Frage, ob das ein binärer Operator ist.
Was hat die Basisklasse Operator für einen Sinn, wenn du später dann solche Fragen stellst?
Funktionalität hochziehen, die nicht in den einzelnen Operatoren ausgeführt werden muss. Die Frage stellt sich, wenn ein Algorithmus in class Operator für eine bestimmte Sorte von Operatoren anders funktioniert, wenn es ich um einen Binären Operator handelt.
Wenn ein Algorithmus für eine bestimmte Sorte von Operatoren anders funktioniert, dann bedeutet das, dass er nicht für alle Operatoren gleich funktioniert. Damit stellt sich unweigerlich die Frage, wieso das Interface des Algorithmus das Gegenteil behauptet, indem es jeden beliebigen Operator entgegen nimmt. (Siehe auch: http://en.wikipedia.org/wiki/Liskov_substitution_principle)
Xin schrieb:
Bei:
[...]
unterscheiden sich class B und class C überhaupt nicht. Du darfst die Instanz bi überall da reinwerfen, wo Du A reinwerfen darfst und bei C musst Du halt ci.a schreiben.
Das ist nicht das gleiche und funktioniert überhaupt nur, weil C::a public ist.
Wenn du tatsächlich der Meinung bist, dass Vererbung und Aggregation äquivalent sind, dann erklär mir, basierend auf dieser Annahme, bitte den Output von folgendem Programm:
#include <iostream> struct A { }; struct B : public A { int b; }; struct C { A a; int b; }; int main() { std::cout << sizeof(A) << '\n' << sizeof(B) << '\n' << sizeof(C) << '\n'; }
Output (MSVC 11 x64):
1 4 8
-
Na das hat doch jetzt eher was mit Optimierung leerer Basisklassen zu tun. Trotzdem ist fuer mich Vererbung der Ausnahmefall und der eingeschlagene Weg von Xin fuer falsch. Es gibt genug Argumente und Beispiele im Internet, rueckblickend finde ich meinen Verzicht auf Vererbung als gut.
-
dot schrieb:
Xin schrieb:
dot schrieb:
Was genau ist der Sinn davon, ein Dokument von Filename erben zu lassen!?
Das ist so nie geschrieben worden.
BitmapDocument erbte von Document, Filename und Bitmap.
Erklär mir bitte, wie das sein kann, dass ein BitmapDocument, das von Document, Filename und Bitmap erbt, nicht von Filename erbt!?
Keine Ahnung wie das sein sollte, wie ich schon schrieb: BitmapDocument erbte von Filenamen.
Document und Filename sind Basisklassen, die grundlegende Konzepte anbieten, BitmapDocument ist die Arbeitsklasse, die diese dann zusammenführt und nutzt.
Ich denke, Du verwechselst hier Document und BitmapDocument. Daher auch die Erklärung auf die Frage, die Du vermutlich stellen wolltest.Alles andere ist bereits erklärt und ich sehe keinen Grund, hier in die Endlosschleife zu gehen.
dot schrieb:
Xin schrieb:
Funktionalität hochziehen, die nicht in den einzelnen Operatoren ausgeführt werden muss. Die Frage stellt sich, wenn ein Algorithmus in class Operator für eine bestimmte Sorte von Operatoren anders funktioniert, wenn es ich um einen Binären Operator handelt.
Wenn ein Algorithmus für eine bestimmte Sorte von Operatoren anders funktioniert, dann bedeutet das, dass er nicht für alle Operatoren gleich funktioniert. Damit stellt sich unweigerlich die Frage, wieso das Interface des Algorithmus das Gegenteil behauptet, indem es jeden beliebigen Operator entgegen nimmt...
Weil es eben nicht nur ein Interface ist, sondern eine Ableitung. Das ist ja gerade der Vorteil der Mehrfachvererbung zum Interface.
Das bedeutet eben, dass Operator Algorithmen anbieten kann, die entsprechend des Interfaces von Operator etwas ausrechnen, was für jeden beliebigen Operator funktioniert.dot schrieb:
Xin schrieb:
Bei:
[...]
unterscheiden sich class B und class C überhaupt nicht. Du darfst die Instanz bi überall da reinwerfen, wo Du A reinwerfen darfst und bei C musst Du halt ci.a schreiben.
Das ist nicht das gleiche und funktioniert überhaupt nur, weil C::a public ist.
Ui, eine Tatsachenbehauptung! Das deutet erstmal deutlich auf eine Meinungsverschiedenheit hin. Wie überraschend.
Wäre es nicht public, wäre es eine andere Semantik. Es funktioniert nicht "nur weil", sondern "genau deswegen, weil" es public ist. Ganz andere Perspektive.
Dies hier führt in eine lange, langweilige Diskussion über den jeweiligen Vergleichsoperation, die mit dem Ergebnis endet, dass Du sagst, dass man das so nicht machen darf und ich frage Dich, wer das Dogma aufgestellt hat und warum mich das interessieren soll und so geht das hin und her und wir landen wieder bei dem wichtigen Punkt, den Du nicht mitzitiert hast: Der Abstimmung auf einen gemeinsam akzeptierte Vergleichsoperation:
Xin schrieb:
Das hängt sehr stark davon ab, was Du unter Aggregation verstehst.
Aggregation ist eine "Haufen von Zeugs" und sagt nix darüber wer hier welche Rechte hat.
Also sparen wir uns das böse Blut, am Ende tun wir eh, was wir jeweils für richtig halten.
Ich muss nachher sowieso langsam mal den ganzen Kram hier raussortieren, denn ich befürchte, dem armen Threadstarter haben wir schon längst irrtümlich und fälschlich vermittelt, dass es chancenlos ist, sinnvoll C++ zu lernen, wenn nichtmals C++-Entwickler sich über Grundlagen einig werden.
-
knivil schrieb:
Na das hat doch jetzt eher was mit Optimierung leerer Basisklassen zu tun. Trotzdem ist fuer mich Vererbung der Ausnahmefall und der eingeschlagene Weg von Xin fuer falsch. Es gibt genug Argumente und Beispiele im Internet, rueckblickend finde ich meinen Verzicht auf Vererbung als gut.
Obgleich dieses Verhalten gemeinhin als "Empty Base Optimization" bekannt ist, handelt es sich dabei imo um viel mehr als eine Optimierung. Die Tatsache, dass diese Optimierung möglich ist, illustriert genau den fundamentalen Unterschied zwischen Vererbung und Aggregation.
Ein Objekt ist etwas, das von anderen Objekten unterschieden werden kann, d.h. es ist eindeutig identifizierbar.
Ein Objekt der Klasse A muss eine Größe > 0 haben, da dies sonst bedeuten würde, dass mehr als ein Objekt den selben Platz einnehmen könnte und die Objekte nichtmehr unterscheidbar wären. Gleichermaßen muss das Subobjekt a eines Objektes der Klasse C eindeutig identifizierbar sein, da es sich ja um ein von einer Instanz von C verschiedenes Objekt handelt. Jedes Objekt der Klasse B ist dagegen allerdings auch ein Objekt der Klasse A und kein separates Objekt...Xin schrieb:
dot schrieb:
Xin schrieb:
dot schrieb:
Was genau ist der Sinn davon, ein Dokument von Filename erben zu lassen!?
Das ist so nie geschrieben worden.
BitmapDocument erbte von Document, Filename und Bitmap.
Erklär mir bitte, wie das sein kann, dass ein BitmapDocument, das von Document, Filename und Bitmap erbt, nicht von Filename erbt!?
Keine Ahnung wie das sein sollte, wie ich schon schrieb: BitmapDocument erbte von Filenamen.
Document und Filename sind Basisklassen, die grundlegende Konzepte anbieten, BitmapDocument ist die Arbeitsklasse, die diese dann zusammenführt und nutzt.
Ich denke, Du verwechselst hier Document und BitmapDocument. Daher auch die Erklärung auf die Frage, die Du vermutlich stellen wolltest.Alles andere ist bereits erklärt und ich sehe keinen Grund, hier in die Endlosschleife zu gehen.
Stimmt, sry, ich wollte eigentlich nach dem Sinn fragen, ein Dokument von Filename abzuleiten und dachte dabei konkret an das BitmapDocument.
-
dot schrieb:
knivil schrieb:
Na das hat doch jetzt eher was mit Optimierung leerer Basisklassen zu tun. Trotzdem ist fuer mich Vererbung der Ausnahmefall und der eingeschlagene Weg von Xin fuer falsch. Es gibt genug Argumente und Beispiele im Internet, rueckblickend finde ich meinen Verzicht auf Vererbung als gut.
Das ist eben nicht einfach nur eine Optimierung, sondern zeigt genau den fundamentalen Unterschied auf.
Ein Objekt ist etwas, das von anderen Objekten unterschieden werden kann, d.h. es ist eindeutig identifizierbar. Ein Objekt der Klasse A muss eine Größe > 0 haben, da dies sonst bedeuten würde, dass mehr als ein Objekt den selben Platz einnehmen könnte und die Objekte nichtmehr unterscheidbar wären. Gleichermaßen muss das Subobjekt a eines Objektes der Klasse C eindeutig identifizierbar sein, da es sich ja um ein von einer Instanz von C verschiedenes Objekt handelt. Jedes Objekt der Klasse B ist dagegen allerdings auch ein Objekt der Klasse A und kein separates Objekt...
Ich mag Deine Argumentation, weil sie zeigt, dass hier eine technischer Unterschied vorliegt. Es ist aber ein Spezialfall: das leere Objekt, hier wird ein Trick verwandt, um die Identifizierbarkeit zu gewährleisten.
Sicher, ein Sonderfall reicht, um seine Argumentation zu begründen, doch hier ist der Sonderfall vor allem eine willkürliche Entscheidung des VC für den Sonderfall, was wie knivil richtig sagt.
knivil schrieb:
Na das hat doch jetzt eher was mit Optimierung leerer Basisklassen zu tun.
Würde sich VC nämlich auf eine einheitliche Darstellung leerer Klassen in allen drei Fällen einigen, was durchaus sinnvoll wäre, dann wäre der VC auch im Sonderfall kein Argument für Deine argumentative Darstellung.
knivil schrieb:
Trotzdem ist fuer mich Vererbung der Ausnahmefall und der eingeschlagene Weg von Xin fuer falsch. Es gibt genug Argumente und Beispiele im Internet, rueckblickend finde ich meinen Verzicht auf Vererbung als gut.
Damit hat keiner ein Problem. Genauso halte ich mein Herangehen für vorteilhaft und baue das weiter aus.
Allerdings wäre ich dankbar, wenn Du mir diese Argumente als PM zur Verfügung stellen könntest, da ich meine Programmiersprache sehr stark auf Vererbung aufbaue und gerne überprüfe, ob ich etwas übersehen habe.Sollte das also nicht nur eine argumentenverstärkende aber leere Worthülse gewesen sein, wäre ich für einen konstruktiven Beitrag dankbar.
-
Xin schrieb:
Ich mag Deine Argumentation, weil sie zeigt, dass hier eine technischer Unterschied vorliegt. Es ist aber ein Spezialfall: das leere Objekt, hier wird ein Trick verwandt, um die Identifizierbarkeit zu gewährleisten.
Sicher, ein Sonderfall reicht, um seine Argumentation zu begründen, doch hier ist der Sonderfall vor allem eine willkürliche Entscheidung des VC für den Sonderfall, was wie knivil richtig sagt.
Es ist eben nicht einfach nur ein technischer Unterschied, sondern ein prinzipieller und der Spezialfall sollte als Illustration dienen. Der Punkt ist nicht, dass ein bestimmter Compiler hier ein anderes Layout generiert (was jeder brauchbare moderne Compiler tun wird). Der Punkt ist, dass ein Compiler hier ein anderes Layout generieren kann, eben weil es sich um zwei rein konzeptionell fundamental verschiedene Dinge handelt. Vererbung modelliert eine "ist-ein" Beziehung (B ist ein A) und Aggregation eine "hat-ein" Beziehung (C hat ein A) und das sind eben zwei völlig orthogonale Konzepte (ein Auto hat vier Räder, aber es ist kein Rad vs. ein Schiff ist ein Fahrzeug aber es hat keine Räder)...
-
dot schrieb:
Es ist eben nicht einfach nur ein technischer Unterschied, sondern ein prinzipieller und der Spezialfall sollte als Illustration dienen. Der Punkt ist nicht, dass ein bestimmter Compiler hier ein anderes Layout generiert (was jeder brauchbare moderne Compiler tun wird).
Er kann den Unterschied so generieren, dass er für Deine Argumentation nicht passt.
Die beiden Argumentationslinien sind orthogonal -> das eine eignet sich nicht um das andere zu begründen. Es trifft sich nur zufälligerweise in dem einen Punkt, den Du aufgezeigt hast.dot schrieb:
Der Punkt ist, dass ein Compiler hier ein anderes Layout generieren kann, eben weil es sich um zwei rein konzeptionell fundamental verschiedene Dinge handelt. Vererbung modelliert eine "ist-ein" Beziehung (B ist ein A) und Aggregation eine "hat-ein" Beziehung (C hat ein A) und das sind eben zwei völlig verschiedene Konzepte (ein Auto hat vier Räder, aber es ist kein Rad vs. ein Schiff ist ein Fahrzeug aber es hat keine Räder)...
Jaja, hatten wir alles schon.
Du hast das Dogma gut verinnerlicht. Ein Fahrrad hat zwei Räder. Ein Fahrrad ist ein Zweirad. Ein Motorrad ist ein Zweirad.
Wieviele Räder hat eigentlich ein Zweirad? Natürlich keine, da ein Fahrrad zwei Räder hat und ein Zweirad ist. Hätte ein Zweirad zwei Räder, hätte ein Fahrrad ja vier...
Hmm... jetzt wird's wieder kompliziert...Alles eine Frage der Perspektive. Du darfst Perspektiven wechseln und das auch modellieren. Am Schluss sollten aber am Fahrrad wie auch Zweirad genau zwei Räder sein. Ob es jetzt zwei Räder hat oder ein Zweirad ist, ist dabei Geschmackssache. Falsch ist aber keins davon, denn es kommt das gleiche raus, nur bei vier Rädern ist was schief gelaufen.
Interessant wird es nur, wenn das Fahrrad ein Zweirad ist, das heimlich ein drittes Rad versteckt hat. Dann "hat es" ein privates Rad... oder ist ein DrittesRadVerstecker... man weiß es nicht
-
Neil deGrasse Tyson schrieb:
The good thing about science is that it's true whether or not you believe in it.
-
Alles eine Frage der Perspektive.
Nein, dein Fahrradbeispiel ist falsch.
Falsch ist aber keins davon, denn es kommt das gleiche raus
Die Richtigkeit am Ergebnis messen, ist ebenfalls falsch und missachtet die Logik.
-
knivil schrieb:
Na das hat doch jetzt eher was mit Optimierung leerer Basisklassen zu tun. Trotzdem ist fuer mich Vererbung der Ausnahmefall und der eingeschlagene Weg von Xin fuer falsch. Es gibt genug Argumente und Beispiele im Internet, rueckblickend finde ich meinen Verzicht auf Vererbung als gut.
Denk ich nicht, für die Optimierung eine nicht genutzten Aggregation/Komposition ist mindestens eine Whole program optimization notwendig, die dann die binär Kompatibilität brechen würde. Stelle sich einer vor, was passiert, wenn man Objekte mit der optimierte Funktion und danach unoptimierte Funktion verwendet. IMO wird das richtiger Datenchaos.
Übrings ist die Ausgabe von GCC identisch.
-
knivil schrieb:
Alles eine Frage der Perspektive.
Nein, dein Fahrradbeispiel ist falsch.
Na, dann freue ich mich auf eine spannende Mail von Dir.
knivil schrieb:
Falsch ist aber keins davon, denn es kommt das gleiche raus
Die Richtigkeit am Ergebnis messen, ist ebenfalls falsch und missachtet die Logik.
Always listen to experts.
They tell you what can't be done and why.Then do it.
(Colin Plumb, wenn ich mich recht entsinne)Ich denke, ich bewege mich durchaus in den Grenzen der Logik. Zumindest programmiere ich so seit einigen Jahren, forciere das auch und komme damit sehr gut voran.
Es gibt hier einen klaren Unterschied: Während ich ein sowohl als auch akzeptiere und beide Methoden gerne nutze, wie sie sich als praktisch erweisen, legst Du Dich auf eins fest.
Wenn Dir das lieber ist, ist das für mich in Ordnung. Aber es wäre schon schön, wenn Du mir entweder irgendwas Inspirierendes mitgeben kannst oder Deine Behauptungen vielleicht argumentativ etwas untermauen könntest. (Mail?)Ansonsten danke ich Dir für die informative Wiederholung bekannter Dogmen und kann weiterhin alles "falsch" machen.
-
Ist dir eigentlich schonmal der Gedanke gekommen, dass du möglicherweise deinem eigenen Dogma unterliegst?
-
dot schrieb:
Ist dir eigentlich schonmal der Gedanke gekommen, dass du möglicherweise deinem eigenen Dogma unterliegst?
Ich unterliege vermutlich vielen Dogmen. Es fiel mir erstmals auf, als man mir Java beibrachte und mir ganz selbstverständlich Dinge erklärte, die ich für absoluten Schwachsinn halte und die Profs ausquetschte und die auch meinten, dass ich falsch liege - aber auch keine Erklärung hatten, warum ich falsch liege.
Die Vermeidung von Mehrfachvererbung ist eins solches Dogma, dem ich nicht mehr unterliege. Übrigens nicht wegen Java, sondern dank diesem Forums, wo man mir dogmatisch erklärte, dass Mehrfachvererbung böse ist und ich das so nicht einsah. Also argumentierte ich dagegen. Damals benutzte ich Mehrfachvererbung aber auch nicht so häufig wie heute. Aber mir fiel in der Diskussion auf, dass das eigentlich ein geiles Feature ist, dem ich viel zu wenig Beachtung geschenkt habe. Da fiel mir auf, wie blödsinnig dieses Dogma ist und ich begann damit rumzuexperimentieren.
Sehr praktisches Feature.
Natürlich unterliege ich Dogmen. Wenn ich an meinem Compiler schreibe und nicht daran gebunden bin, was die Sprache mir offenbar vorgibt, kann ich auch mit Konstrukten spielen, die in C++ nicht üblich sind. Und auf einmal fällt einem auf, dass man ganz selbstverständlich Dinge hinnimmt, obwohl es eigentlich keinen Grund dafür gibt. Es muss nur einer irgendwann mal für wichtig empfunden worden sein und der hat was gesagt und die Welt käut es wieder.
Sehr schön fand ich die Begründung, warum C# kein Const-Correctness unterstützt. Warum das im Design fehlt, hat der C#-Entwickler beschrieben. Und wenn der das sagt, dann ist vollkommen klar, dass ich als Const-Correctness-Fanatiker ja wohl nur ein Spinner bin. Der C#-Entwickler hat das ja wohl klar begründet, dass Const-Correctness Schwachsinn ist.
Und hier bin ich halt der Spinner mit der Mehrfachvererbung.