Is a beziehung
-
Bashar schrieb:
Dass ein Kreis eine Ellipse ist, stimmt nur für unveränderliche Objekte.
Genau dazu wollte ich gerade was schreiben: wenn man die Objekte "immutable" macht, also unveränderlich, dann kann man Kreis von Ellipse ableiten.
-
class Ellipse{ public: setRadius(int x) setRadius(int y) }; class Kreis:public Ellipse { setRadius(int x) setRadius(int y) };Ich habs immer noch net ganz verstanden. Ist das Problem folgendes:
Ellipse braucht 2 funktionen zum Setzen der Halbachsen.
Der Kreis braucht allerdings nur 1 Funktion , nämlich setzen des Radius.
Trotzdem muss er beide überschreiben obwohl er ja nur eine braucht.Und das ist wohl dann das Problem ?
-
Autsch. Du musst den Methoden unterschiedliche Namen geben, wie du die Parameter nennst, ist egal.
Das Problem ist dann Folgendes:
Ellipse e; Kreis k; e.width = e.height = 10; k.width = k.height = 10; e.width = 20; k.width = 20;Dann ist e.height = 10, aber k.height = 20. Also verhält sich ein Kreis nicht wie eine Ellipse.
-
Ein "gutes" Beispiel:
Ein Kraftfahrzeug kann man starten und man kann damit fahren. Daher gemeinsame Basis:
class Kraftfahrzeug { void start(); void fahren(); }; class LKW : public Kraftfahrzeug { //...LKW Zeugs }; class Motorrad : public Kraftfahrzeug { //...Motorrad Zeugs }; class Auto : public Kraftfahrzeug { //...Auto Zeugs }; void benutzeKFZ(Kraftfahrzeug & kfz) //soll beliebige KFZ-Typen benutzen { kfz.start(); kfz.fahren(); } LKW lkw; Motorrad motorrad; Auto auto; //jaja... benutzeKFZ(lkw); //okay, lkw *ist* ein KFZ benutzeKFZ(mottorrad); //okay, mottorrad *ist* ein KFZ benutzeKFZ(auto); //okay, auto ist *ist* KFZSchlechtes Beispiel:
Im mathematischen Sinne ist Kreis zwar eine Spezialisierung von Ellipse, im onjektorientierten Sinne nicht:
class Ellipse { void setX(); void setY(); }; class Kreis : public Ellipse { //irgendwie wird hier setY entfernt }; void benutzeEllipse(Ellipse & e) //soll beliebige Ellipsentypen benutzen { e.setX(x) e.setY(y) } Ellipse e; Kreis k; benutzeEllipse(e); //okay benutzeEllipse(k); //boing... Kreis ist *keine* Ellipse, weil kein setY
-
Die Ellipse hat eine Methode die der Kreis nicht braucht, deswegen
ist der Kreis objektorientiert gesehen keine Ellipse.
-
blurry333 schrieb:
Die Ellipse hat eine Methode die der Kreis nicht braucht, deswegen
ist der Kreis objektorientiert gesehen keine Ellipse.Nicht nur, dass er sie nicht braucht, sie ist einfach FALSCH. Man kann mit einem Kreis nicht das gleich machen, was man mit einer Ellipse machen kann. Man kann die beiden also nicht beliebig austauschen.
-
blurry333 schrieb:
Die Ellipse hat eine Methode die der Kreis nicht braucht, deswegen
ist der Kreis objektorientiert gesehen keine Ellipse.Nein, die Ellipse hat Eigenschaften die ein Kreis nicht hat (und daher auch nicht bekommen darf). Wie das umgangen wird sei dahin gestellt. Allerdings kann der Kreis nicht in allen Fällen als Ellipse eingesetzt werden.
Es könnte ja sein das der Entwickler von Ellipse setX und setY überschreibt:class Ellipse { float x, y; public: virtual void setX(float value) { x = value; } virtual void setY(float value) { y = value; } float getArea() const { return ... } }; class Kreis : public Ellipse { public: void setX(float value) { Ellipse::setX(value); Ellipse::setY(value); } void setY(float value) { Ellipse::setX(value); Ellipse::setY(value); } };Ein anderer Autor will jetzt die Methode foo(Ellipse&) verwenden und übergibt hier eine Instanz von Kreis (weil Kreis ist ja eine Ellipse):
Kreis bar; foo(bar);void foo(Ellipse& e) { e.setX(20); e.setY(10); assert(e.getArea() == 157.079f); }Der Autor von foo trifft allerdings eine Annahme, nämlich das die zurückgelieferte Fläche der einer Ellipse mit den achsen 10 und 20 entspricht. Für den Kreis wird allerdings 10^2*Pi geliefert, also nicht ganz den Erwartungen entsprechend...
-
Wenn man die Ellipse als gestreckten Kreis betrachtet, könnte man sie vom Kreis erben lassen:
struct Kreis { double radius; Kreis(double radius); virtual ~Kreis(); virtual double getArea() const { return radius * radius * PI; } }; struct Ellipse : public Kreis { double xstreckung; Ellipse(double radius, double xstreckung) : Kreis(radius) , xstreckung(xstreckung) { } virtual double getArea() const { return Kreis::getArea() * xstreckung; } };Natürlich ist eine Ellipse nicht im den Sinne ein Kreis, dass sie sich genauso verhält. Die Ellipse erweitert den Kreis um eine weitere Eigenschaft. Dabei kann sie sich aber auch genau wie ein Kreis verhalten, nämlich wenn (im Beispiel oben)
Ellipse::xstreckung1.0ist.
-
blurry333 schrieb:
Die Ellipse hat eine Methode die der Kreis nicht braucht, deswegen ist der Kreis objektorientiert gesehen keine Ellipse.
Ja, das ist des Rätsels Lösung.
Würde man diese Funktion bei Ellipse übrigens auch nicht brauchen, dürfte man wieder vererben. Man müßte sich aber klar sein, daß man sie auch in Zukunft nicht brauchen wird. Das bewußte Weglassen von Sachen, die die Außenweltbegriffe können, aber unsere Modellbegriffe nicht, ist ein wichtiger Teil der Softwareentwicklung und sollte nicht einfach aus Versehen passieren oder ignoriert werden. Die Modellbegriffe werden dann nach C++ übersetzt und Klassen genannt. Ignoriert man diese Modellierung, sondern versucht unvernünftigerweise die Außenwelt in Klassen einzufangen, darf man praktisch niemals eine Klasse von einer anderen erben lassen, weil es in der Außenwelt so viele gemeine Ausnahmen gibt, Säugetiere mit doch nicht sieben Halswirbeln, Säugetiere, die doch Eier legen, Automobile mit drei Rädern, Lehrer, die keinen Unterricht halten...
Und das wollen wir doch alle nicht, oder?
-
TyRoXx schrieb:
Wenn man die Ellipse als gestreckten Kreis betrachtet, könnte man sie vom Kreis erben lassen:
struct Kreis { double radius; Kreis(double radius); virtual ~Kreis(); virtual double getArea() const { return radius * radius * PI; } }; struct Ellipse : public Kreis { double xstreckung; Ellipse(double radius, double xstreckung) : Kreis(radius) , xstreckung(xstreckung) { } virtual double getArea() const { return Kreis::getArea() * xstreckung; } };Natürlich ist eine Ellipse nicht im den Sinne ein Kreis, dass sie sich genauso verhält. Die Ellipse erweitert den Kreis um eine weitere Eigenschaft. Dabei kann sie sich aber auch genau wie ein Kreis verhalten, nämlich wenn (im Beispiel oben)
Ellipse::xstreckung1.0ist.Ja, geht andersrum auch.
class Ellipse { float x, y; public: Ellipse(fload _x, float _y){ x=_x; y=_y; } float getArea() const { return PI*x*y; } }; class Kreis : public Ellipse { public: Kreis(floar r):Ellipse(r,r) //getArea() darf geerbt werden };Aber mit dem setX und setY macht man alles kaputt.