Ein Prinzip der Objektorientierung ist das Vererben von
Attributen und Methoden einer Klasse an eine davon abgeleitete,
speziellere,
Klasse. Sehen wir uns das Beispiel an:
// Klasse für
Obst
class CFruit
{
public: // folgende
Elemente sind
öffentlich
// Konstruktor: Standardfarbe schwarz
CFruit()
{ m_r = m_g = m_b = 0.0f; }
// Destruktor vituell, d.h. alles
klar zum Ableiten
virtual
~CFruit()
{ }
// Methode
verändert
keine Werte, darum const
void
printColor() const
{ cout << m_r
<< " " << m_g
<< " "
<< m_b << endl; }
protected: //
folgende Elemente sind
geschützt
float m_r,
m_g, m_b; // Farbwerte
};
Alle Methoden wurden der Lesbarkeit halber
hier inline innerhalb
der Klasse definiert. inline-Funktionen werden normalerweise
aus Geschwindigkeitsgründen verwendet. Anstatt einen Funktionsaufruf zu tätigen, werden inline-Funktionen mittels
cut-and-paste direkt in den aufrufenden Code hineinkopiert. Hier dienen
sie, wie gesagt nur der Kürze des Codes.
Diese Klasse funktioniert ohne Probleme und stellt eine
schwarze Frucht dar, deren Farbe ausgegeben werden kann. Sie besitzt
drei geschützte Attribute für die Farben rot,
grün und blau. Darüber hinaus fällt noch
auf, dass
die Methode printColor hinter der Deklaration ein const
trägt. An dieser Stelle besagt const,
dass die Methode keine Parameter der Klasse verändert. Wir
werden es weiter unten darauf zurückkommen.
Apfel ist Obst
Apfel ist sicher eine Unterform von Obst mit einer
speziellen Farbe, etc. Leiten wir also die Klasse der Äpfel
aus der Klasse Obst ab...
// Klasse für Äpfel (alles von
CFruit
öffentlich erben)
class CApple : public
CFruit
{
public: // folgende
Elemente sind öffentlich
CApple()
{ m_r = 0.0f; m_g = 1.0f; m_b = 0.0f; }
virtual
~CApple()
{ }
};
Was hier passiert ist folgendes: Die Klasse CApple
erbt alle Methoden und Eigenschaften der Klasse CFruit.
Das bedeutet im Grunde, dass Methoden und Attribute für
CApple genau so existieren, wie
für CFruit.
Es bedeutet unter
anderem, dass wir auf die Farbattribute zugreifen dürfen,
obwohl sie hier gar nicht auftauchen, sondern weiter oben in der
Deklaration einer anderen Klasse. Die Farbattribute waren als protected
deklariert. Auf alle als public
und protected
deklarierten
Klassenelemente darf die Unterklasse unbegrenzt zugreifen. Auf Elemente
der Oberklasse, die unter der Rubrik private
stehen, haben nicht einmal abgeleitete Objekte Zugriff.
Konstruktor und Destruktor werden nicht eins zu eins
vererbt, sondern rekursiv aufgerufen. Das bedeutet, dass bei
Erzeugen
einer Instanz der Apfelklasse zuerst der CFruit
Standardkonstruktor
aufgerufen wird und danach der
CApple Konstruktor. Bei den Destruktoren
(die virtuell sein müssen!) geht diese Aufrufkette
rückwärts. Zunächst wird der Destruktor von
CApple aufgerufen, danach der von CFruit.
Im Beispiel gibt es die Funktion printColor,
die in der Lage ist, die
Farbe einer beliebigen
Frucht auszugeben.
void
printColor(CFruit fruit)
{
fruit.printColor();
}
Dieser Funktion können wir nun Äpfel oder generische
(schwarze) Früchte übergeben:
int main()
{
// generische Frucht und
Apfel erzeugen
CFruit fruit;
CApple apple;
// von allen
Früchten die
Farbe ausgeben
printColor(fruit);
printColor(apple);
return 0;
} // main()
Innerhalb der printColor-Funktion
besitzen wir nur Zugriff auf die Elemente von CFruit,
die allerdings in diesem sehr simplen Beispiel mit der von CApple
übereinstimmen. Sinnvoller wird das Ganze, wenn wir mehrere
Klassen von
einer Grundklasse ableiten, wozu wir im nächsten Kapitel
kommen.
Selbständige
Programmierung
- Deklariere die Farbattribute in CFruit als private:
und sieh, was der Compiler dazu meint.
- Gebe in Konstruktor und Destruktor der Klassen
einen Text aus. Was passiert beim Aufruf der Funktion
printColor?
zurück