Vererbung: Rechteck und Quadtrat!?



  • Was Wikipedia unter obigem Link zum Thema schrieb:

    Zu beachten ist hierbei, dass die Entscheidung jeweils abhängig vom konkreten Fall ist. Ist beispielsweise eine Manipulation der geometrischen Figur nach der Erzeugung nicht vorgesehen, so kann Kreis durchaus von Ellipse abgeleitet sein: Dann ist "die Achsen können unabhängig voneinander skaliert werden" keine Eigenschaft der Klasse Ellipse, und somit muss sie auch keine Eigenschaft von Kreis sein, um Kreis zur Unterklasse von Ellipse zu machen.

    Damit waere dann auch schon wieder ne Menge gesagt.

    Zugegeben, mit HumeSikkins Argumenten macht es nicht unbedingt Sinn, ein Quadrat von einerm Rechteck abzuleiten, wenn denn das Rechteck die Settermethoden deklariert. Sollte sowas noetig sein, dann kann man es wieder wie mit dem Pinguin und dem Vogel halten: Man bilde eine Klasse mathRect , leite davon mathSquare und concreteRect ab sowie concreteSquare von mathSquare . Wobei die beiden Konkreten Klassen die Settermethoden etc. beinhalten, die math* Klassen jedoch nur den mathematischen Aspekt beinhalten, naemlich dass ein Rechteck ein Viereck mit 4 rechten Winkeln und 2 Kantenlaengen ist, und ein Quadrat wiederum ein Rechteck mit 2 gleichen Kantenlaengen ist.
    Ob die konkreten Klassen dann von den mathematischen ableiten oder diese nur beinhalten ist wieder ein anderes Thema.
    Ich bleibe jedoch dabei, dass man, wenn man nur die mathematischen Aspekte betrachtet, ein Quadrat durchaus von einem Rechteck ableiten kann. (Getter und Setter sind keine mathematischen Aspekte)



  • OK, darauf können wir uns einigen - bei immutablen Klassen macht die Verwandschaftsbeziehung Sinn (aber die meisten Programmierer arbeiten mit veränderbaren Rechtecken und Quadraten - und dann sollte man die Verwandschaft in Frage stellen).



  • Also die landläufige Meinung, das Vögel fliegen können, ist falsch.
    Ergo kann man Pinguin, Kiwi, Strauss, Emu, Amsel, Star und Fink von Vogel ableiten.

    Alle haben den selben Aufbau, sie haben Flügel, sie haben Federn.
    Selbst Pinguine, welche übrigens unter Wasser fliegen, mittels Flügelschlag.

    Und Quadrat vs. Rechteck ist imho auch leicht: Wozu eine Klasse Quadrat, wenn es nur ein Sonderfall des Rechtecks ist?
    Fürs was rechtfertigt sich hier eine eigene Klasse? (Abgesehen davon, das man eine Variable für die Breite sich einsparen kann, weil ein Quadrat gleich hoch und breit ist.)



  • phlox81 schrieb:

    Fürs was rechtfertigt sich hier eine eigene Klasse? (Abgesehen davon, das man eine Variable für die Breite sich einsparen kann, weil ein Quadrat gleich hoch und breit ist.)

    die invariante height==width



  • Warum ableiten? Was hat ein Quadrat für Funktionen die ein Rechteck nicht hat?



  • seh ich auch so schrieb:

    Warum ableiten? Was hat ein Quadrat für Funktionen die ein Rechteck nicht hat?

    Darum geht es nicht, der Punkt ist, dass man sich bei einer Ist-Ein-Beziehung auch ganz gut täuschen kann.



  • Jein. Das Problem ist, dass unsere gemeine Sprache nicht genau genug ist, so dass die Behauptung "Ein Quadrat ist ein Rechteck" wahr und falsch sein kann, je nachdem was wir unter Quadraten und Rechtecken verstehen. Auf der anderen Seite ist C++ sehr genau, so dass wir mit einem simplen

    class Quadrat : public Rechteck
    

    manchmal mehr sagen als wir eigentlich zu sagen glauben. Und daher ist dort Vorsicht gefragt.



  • "Ein Quadrat ist ein Rechteck" wahr und falsch sein kann

    Na von wegen ... Was soll den an der Aussage falsch sein? Ich kann auch sagen, wenn vor mir nen quadratischer Körper ist, das er rechteckig ist.



  • (D)Evil schrieb:

    "Ein Quadrat ist ein Rechteck" wahr und falsch sein kann

    Na von wegen ... Was soll den an der Aussage falsch sein? Ich kann auch sagen, wenn vor mir nen quadratischer Körper ist, das er rechteckig ist.

    Du liest am besten mal den Thread von vorne.



  • pumuckl schrieb:

    Das Problem ist, dass unsere gemeine Sprache nicht genau genug ist, so dass die Behauptung "Ein Quadrat ist ein Rechteck" wahr und falsch sein kann, je nachdem was wir unter Quadraten und Rechtecken verstehen.

    sag nicht 'ein quadrat ist ein rechteck' sondern sag' 'ein quadrat ist die erweiterung eines rechtecks' und dann merkst du schnell, dass der satz falsch ist (auch umgekehrt), denn mit vererbung kann man zwar etwas dazupacken, aber nichts wegnehmen.



  • @Bashar: Hmm ... tjo hab das schon zum groß Teil gelesen. Finde aber trotzdem keinen haltbaren Argumentationspunkt, ein Quadrat als gesonderten Fall anzusehen. Es sei denn du brauchst die besonderen Definitionen die nur bei einem Quadrat zutreffen. Quadrat ist nunmal laut Definition ein Rechteck**.** Von daher ist eine Basisklasse Rechteck, von der man keine Klasse Quadrat ableiten kann, falsch implementiert. Von Quadrat auf Rechteck ist es nat. anders ...



  • Und was genau ist dein Gegenargument? Es ging um die Methoden setWidth/setHeight eines Rechtecks, die man nicht korrekt in einem Quadrat implementieren kann. Ein Objekt ist nunmal in der OOP nicht nur ein bestimmtes Ding, sondern auch das, was man damit machen kann.
    Man könnte höchstens argumentieren (vielleicht tust du das ja, ohne es zu sagen), dass Rechteck dann eben diese Methoden nicht haben darf. Dann ist natürlich trivial jedes Quadrat auch ein Rechteck, die Frage, woran man solche Problem im Allgemeinen erkennt, bleibt aber bestehen.



  • Ich sehe nicht wo dein Problem ist? Die Funktion setWidth und setHeight würden halt im Quadrat überschrieben ... z.B. gibt es auch eine Basisklasse Tier. Wenn die nun die Funktion laufen hätten, würdest du bei manchen(den meisten) wohl auch die lauf-Funktion überschreiben müssen ... setWidth und setHeight würden im Quadrat das selbe machen, und zwar m_nHeight und m_nWidth auf den übergeben Wert setzen ... wo ist da euer Problem?



  • (D)Evil schrieb:

    Ich sehe nicht wo dein Problem ist? Die Funktion setWidth und setHeight würden halt im Quadrat überschrieben ... z.B. gibt es auch eine Basisklasse Tier. Wenn die nun die Funktion laufen hätten, würdest du bei manchen(den meisten) wohl auch die lauf-Funktion überschreiben müssen ... setWidth und setHeight würden im Quadrat das selbe machen, und zwar m_nHeight und m_nWidth auf den übergeben Wert setzen ... wo ist da euer Problem?

    Das ist schlechtes OOP! Eine abgeleitete Klasse macht Zusicherungen über Attribute der Oberklasse. Das Liskovsche Substitutionsprinzip wird verletzt.
    Programmier doch mal eine Methode, die ein Rechteck derart verzerrt, dass es bei gleichem Flächeninhalt die Breite 1 hat. Und dann finde heraus, ob diese Methode mit Quadraten funktioniert.

    tfa



  • jedes rechteck ist ein quadrat, aber ist jedes quadrat auch ein rechteck? wie war das mit der vererbung?



  • (D)Evil schrieb:

    Ich sehe nicht wo dein Problem ist? Die Funktion setWidth und setHeight würden halt im Quadrat überschrieben ...

    Wenn du sie so überschreibst, dass sie dafür sorgen, dass width == height immer gilt, kannst du ein Quadrat nicht mehr allgemein überall einsetzen, wo ein Rechteck erwartet wird.
    Überschreibst du sie nicht, bleibt ein Quadrat nicht lange ein Quadrat.
    Warum wiederhole ich das eigentlich für dich? Das wird hier doch von Anfang an diskutiert.



  • Hi,

    ich denke, ein Problem dabei ist, dass es im "echten Leben" "Spezialisierung" eigentlich immer heißt: Reduzierung von Freiheitsgraden. (="Hinzufügen von Invarianten").

    In den mir bekannten OO-Sprachen aber bedeutet "Ableiten" "Hinzufügen von Eigenschaften": Man kann kein "SetWidth()" mehr wegmachen, sondern nur Neues hinzufügen (oder ggf. Funktionalität via overriding umdefinieren).

    Deswegen passt oftmals "Spezialisierung via Ableiten" nicht.
    So auch in diesem Fall.

    Gruß,

    Simon2.


Anmelden zum Antworten