001
21.10.2015, 10:47 Uhr
ao
(Operator)
|
Du hast es schon sehr gut verstanden, aber dein Modellansatz ist fehlerhaft. Die Klasse Tier hat virtuelle Methoden Schwimmen() und Fliegen(), das heißt, dass in deiner Welt jedes Tier schwimmen und fliegen kann. Das ist aber nicht der Fall, und damit kommt dein Modell in Konflikt mit der Wirklichkeit.
Zitat: |
Für mich wäre es logischer, wenn die Basisklasse nur ganz allgemeine Methoden zur Verfügung stellen würde, die alle Tiere gemeinsam haben, wie z.B. "Fressen", "Bewegen", "Fortpfanzen" etc. Und in den abgeleiteten Klassen würden zusätzliche Fähigkeiten (Methoden) definiert, wie "Fliegen", "Metamorphose", "NetzSpinnen" usw...
|
Richtig. Also etwa so:
C++: |
class Tier { public: virtual void Fressen () = 0; virtual void Bewegen () = 0; };
class Goldfisch : public Tier { public:
virtual void Fressen () { std::cout << "Goldfisch frisst." << std::endl; }
virtual void Bewegen () { std::cout << "Goldfisch schwimmt." << std::endl; } };
class Spinne : public Tier { public: virtual void Fressen() { std::cout << "Spinne frisst." << std::endl; } virtual void Bewegen() { std::cout << "Spinne krabbelt." << std::endl; }
void NetzSpinnen () { std::cout << "Spinne spinnt ein Netz." << std::endl; }
};
|
Beide Tierarten können fressen und sich bewegen. Dass sie sich auf unterschiedliche Weise bewegen (schwimmen bzw. krabbeln), nennt man im objektorientierten Sprech "Polymorphie": Die polymorphe Methode Bewegen hat in allen abgeleiteten Klassen dieselbe Signatur, sieht also für den Compiler immer gleich aus, tut aber was Unterschiedliches.
Zitat: |
So muss die Basisklasse Tier, bei jedem weiteren abgeleiteten Tier das zusätzliche Fähigkeiten besitzt, auch selbst um diese Methoden erweitert werden. Sonst können ihre speziellen Fähigkeiten nicht über den Basisklassenzeiger aufgerufen werden.
Auch der Zugriff auf die abgeleiteten Klassen über den Basisklassenzeiger ist für mich nicht ganz schlüssig. So ist es möglich "goldbarsch->Fliegen()" aufzurufen, obwohl der Goldbarsch keine Methode (Fähigkeit) dafür besitzt.
|
Über den Basisklassenzeiger können (und sollen) nur Eigenschaften und Fähigkeiten aufgerufen werden, die allen Tieren gemeinsam sind. Fliegen gehört nicht dazu, deswegen hat es in der Basisklasse nichts verloren. Fliegen kann nur typsicher an der Klasse Elster aufgerufen werden.
Es ist nicht richtig, dass die Basisklasse die Vereinigungsmenge aller abgeleiteten Klassen ist. Die Basisklasse ist die Schnittmenge.
Wahrscheinlich wird man dieses Modell weiterentwickeln und folgendes bauen:
C++: |
class Vogel : public Tier { public: virtual void Fliegen (); };
class Elster : public Vogel {}; class Geier : public Vogel {};
|
Also eine weitere Basisklasse Vogel zwischen Tier und den einzelnen Vogelarten. Über einen Vogel*-Pointer kann man dann alle Vögel hochfliegen lassen, und die Fische und Spinnen bleiben am Boden.
Zitat: |
Oder gibt es noch andere Vererbungsmuster die logischer und leichter zu verstehen sind?
|
Man muss drauf achten, dass man die Eigenschaften und Fähigkeiten der realen Objekte richtig modelliert. Das ist oft einfacher gesagt als getan, aber genau das ist das Faszinierende und Spannende am Softwareentwurf: Rausfinden, in welchen Beziehungen die Objekte stehen, mit denen man hantiert, und das richtig in einer Programmiersprache abbilden.
Wenn man merkt, man kann mit seinen Objekten komische Sachen machen (Fische fliegen lassen zum Beispiel), dann hat man wahrscheinlich einen Entwurfsfehler gemacht. Den sollte man umgehend korrigieren, sonst fällt einem das später auf die Füße.
Außer der Vererbung mit Klassen gibt es noch die Interface-Technik. Solltest du dir mal anlesen. In modernen Sprachen (Java, C#) gibt es dafür eigene Schlüsselwörter und auch etwas abweichende Regeln. C++ ist da leider ein bisschen veraltet, da werden Interfaces mit Hilfe abstrakter Basisklassen realisiert, was die Unterschiede etwas verwischt. Dieser Post wurde am 21.10.2015 um 10:52 Uhr von ao editiert. |