Twitter und Facebook-Anbindung
X
Tweet Follow @twitterapi
!!! Anbindung an twitter und facebook öffnen !!!

Wenn Ihnen mein Online-Buch gefällt,
dann bedanken Sie sich doch mit einer kleinen Spende...

20.3 Wozu braucht man Polymorphismus

20.3 Wozu braucht man Polymorphismus

Stellen Sie sich vor, Sie bauen tatsächlich ein Rennspiel mit den von mir gezeigten Klassen. Nun wollen Sie die Logik für das eigentliche Rennen bauen, in welchem beliebige Fahrzeuge gegeneinander antreten sollen. Nun hat man zunächst ein Problem. Selbst wenn man die Anzahl der Fahrzeuge festsetzt, muss man immer noch verschiedene Typen in Variablen unterbringen, wobei der Typ aber erst zur Laufzeit feststeht. Genau hier kommt der Polymorphismus ins Spiel und das ursprüngliche Problem ist keines mehr. Sie erzeugen sich also das gewünscht Fahrzeug (egal ob Mercedes oder Harley Davidson) und speichern es in einem Array, welches Fahrzeuge aufnehmen kann.

In folgender Grafik habe ich dies mal Schematisch dargestellt. Wichtig dabei ist, dass die Objekte, trotz der Typumwandlung, intern erhalten bleiben, auch wenn man nicht mehr auf alle Attribute und Methoden zugreifen kann.

Schematische Darstellung für einen Polymorphismus

Das eigentlich geniale daran kommt aber noch. Wenn die Klasse "CFahrzeug" eine virtuelle Methode "Zeichnen" bereitstellt und alle anderen Klassen diese überschreiben, kann man sich den Downcast sparen, um jene Methode aufzurufen. Intern bleiben die Objekte wie sie ursprünglich waren und da sie eine virtuelle Tabelle besitzen, weiß der Computer, dass er nicht die Methode des Fahrzeuges, sondern des gewünschten Objektes aufrufen soll. In jener Methode stehen dann auch wieder die einzigartigen Attribute und Methoden der einzelnen Klasse zur Verfügung. Man braucht sich also nicht zu merken, an welcher Stelle im Array was steht. Nur wenn man auf Sachen zugreifen will, die nicht in der Basisklasse stehen, muss man wieder explizit Downcasten und man muss sich somit merken, was wo stand. Hier mal ein Beispiel.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
					
class CFahrzeug { 
	public:
		virtual void Aktualisieren() {
			printf("CFahrzeug::Aktualisieren\n");
		} // Aktualisieren
};

class CAuto : public CFahrzeug {
	public:
		virtual void Aktualisieren() {
			printf("CAuto::Aktualisieren\n");
		} // Aktualisieren
};

class CMotorrad : public CFahrzeug {
	public:
		virtual void Aktualisieren() { 
			printf("CMotorrad::Aktualisieren\n");
		} // Aktualisieren
};

// ...

CFahrzeug*	aFahrzeuge[3];
CFahrzeug*	pFahrzeug	= new CFahrzeug();
CAuto*		pAuto		= new CAuto();
CMotorrad*	pMotorrad	= new CMotorrad;

aFahrzeuge[0]			= pFahrzeug;	// Suchen der richtigen Methode
aFahrzeuge[1]			= pAuto;	// Suchen der richtigen Methode
aFahrzeuge[2]			= pMotorrad;	// Suchen der richtigen Methode

aFahrzeuge[0]->Aktualisieren();
aFahrzeuge[1]->Aktualisieren();
aFahrzeuge[2]->Aktualisieren();

delete aFahrzeuge[2];
delete aFahrzeuge[1];
delete aFahrzeuge[0];
					

Ausgabe:

CFahrzeug::Aktualisieren
CAuto::Aktualisieren
CMotorrad::Aktualisieren
		

Wie Sie sehen konnten, habe ich eine ganz ganz spartanische Implementierung der drei Klassen "CFahrzeug", "CAuto" und "CMotorrad" vorgenommen und lediglich eine virtuelle Methode namens "Zeichnen" implementiert, wobei jene nur den eigenen Klassennamen auf der Konsole ausgibt. Anschließend erzeuge ich ein Array, welches Fahrzeuge aller Art aufnehmen kann, sowie drei Objekte (je eines pro Klasse), welche ich in das Array einhänge. Anschließend rufe ich die Methode auf und man sollte meinen, da es sich jetzt allgemein um Fahrzeuge handelt, dass immer "CFahrzeug::Aktualisieren" ausgegeben wird. Dank der virtuellen Tabelle eines jeden Objektes, wird aber immer die eigene Methode aufgerufen und die Ausgabe entspricht den jeweiligen Klassennamen. Falls eine Klasse die gewünschte Methode nicht implementiert, wird die Methode der Basisklasse aufgerufen.

Hier sollte aber eines schon auffallen. Genau weil man nur Sachen aufrufen kann, die in der Basisklasse vorkommen, neigt man dazu, immer mehr Code so variabel zu gestalten, dass man ihn in eine Basisklasse verschieben kann. Das hat zur Folge, dass die Kindklassen irgendwann nur noch zu Datencontainern werden. Dann stellt sich wieder die Frage, ob man wirklich Vererbung braucht. Wie angedeutet, braucht man virtuelle Methoden, welche die Bearbeitung von Objekten langsamer macht. Sie sollten also nicht auf Teufel komm raus eine Basisklasse bauen, nur um all Ihre Objekte in einem Array halten zu können. Schaffen Sie nur da eine Basisklasse, wo es vom reinen Sprachgebrauch auch sinnvoll wäre. Auto und Fahrzeug ist noch sinnvoll, aber wenn man jetzt einen Mensch hat und möchte Mensch und Fahrzeug gleichzeitig verwalten, macht es nicht viel Sinn, eine Klasse "CDingsda" zu erzeugen. Später weiß keiner mehr, was damit gemeint ist. Sicher könnte man diese Klasse auch "C3DModel" nennen und das wäre zu mindestens sinnvoller bzw. nachvollziehbarer. Trotzdem sollten Sie solche Scherze vermeiden, da im allgemeinen Verständnis ein Fahrzeug nicht wirklich etwas mit einem Menschen zu tun hat (abgesehen davon, das er es fährt, aber dann würde man eher eine Aggregation als eine Vererbung annehmen).

Zum Seitenanfang
Zum Inhaltsverzeichnis

© Copyright by Thomas Weiß, 2009 - 2012