C++ Vererbung und Polymorphie

Werbung
C++
Vererbung und Polymorphie
Vortrag von Anke Schulz 27.7.2000
Vererbung



Die Vererbung ermöglicht es neue Klassen auf der Basis
von schon bestehenden Klassen zu definieren.
Wie sinnvoll und praktisch das ist haben wir schon bei
Java gesehen.
Im Unterschied zu Java ist es bei C++ möglich eine neue
klasse von mehreren Basisklassen abzuleiten, die dann die
Eigenschaften aller dieser Basisklasssen besitzt.
Und natürlich all die Eigenschaften, die man neu dazu
definiert.
Syntax

class klassenname :
[virtual][public, protectet, private] Basisklassenname1,
[virtual][public, protectet, private] Basisklassenname2
{
Liste der klassenelemente
};

Die Zugriffsspezifizierer public, protectet und private regeln bei der
Vererbung nicht den Zugriff aus den Methoden der abgeleiteten Klassen auf
die geerbten Elemente, dies wird ja schon in der Deklaration in der
Basisklasse geregelt und gilt hier also immernoch, sondern welche
Zugriffsrechte die abgeleitete Klasse für die geerbten Elemente nach außen
weiter gibt. Z. B. wenn über ein Objekt der abgeleiteten Klasse auf diese
Elemente zugegriffen wird.
Virtual ist nur bei Mehrfachvererbung interessant.

Zugriffsbeschränkung

Ausschlaggebend sind also die Zugriffsrechte, die in der Basisklasse
vorgesehen waren, diese können dann in der abgeleiteten Klasse durch
die Zugriffsspezifizierer dort nur verschärft werden.

Zugriffsspez. der Vererbung
public
protectet
private
Basisklasse
public
protectet
private
public
protectet
private
private
private
abgeleitete Klasse
public
protectet
private
protectet
protectet
private
private
private
Beispiel



class Basis {
int w_priv;
//private
public:
int w_pub;
};
class Abgeleitet :private Basis {
public:
void fkt() {
w_priv = 2;
// kein Zugriff, private
w_pub = 2;
// ok
}
};
int main() {
class Abgeleitet obj;
cout<<obj.w_pub<<endl; //kein Zugriff, private- Vererbung
return 0;
}
Zugriffsrecht lockern

Zugriffsbeschränkungen durch die Vererbung können in der
abgeleiteten Klasse explizit wieder gelockert werden. Eine geerbte
Eigenschaft kann aber keine weitreichendere Zugänglichkeit
zugewiesen werden, als sie in der Basisklasse besitzt.

Beispiel

class Basis {
int
public:
int
int
int
};
w_priv;
w_pub1;
w_pub2;
w_pub3;
//private
Fortsetzung des Beispiels

class Abgeleitet :private Basis {
public:
Basis::w_pub1;
//ist wieder public
using Basis::w_pub2; //ist wieder public
};

int main() {
class Abgeleitet obj;
cout<<obj.w_pub1<<endl;
cout<<obj.w_pub2<<endl;
cout<<obj.w_pub3<<endl;
cout<<obj.w_priv<<endl;
return 0;
}
//ok
//ok
//kein Zugriff
//kein Zugriff
Vererbung - Einbettung



Um in einer Klasse die Eigenschaften einer anderen nutzen zu können
gibt es neben der Vererbung und der friend- Deklaration(siehe
Vortrag von Marc) die Möglichkeit der Einbettung.
Die Entscheidung ob Vererbung oder Einbettung sinnvoller ist hängt
von der Beziehung ab, in der die Objekte zueinander stehen.
Kann man ein Objekt der Klasse Y auch als Objekt der Klasse X
betrachten, dann handelt es sich um Vererbung.
Oder gehört zu einem Objekt der Klasse X auch ein Objekt der Klasse
Y, dann ist Einbettung sinnvoll.
Vererbung - Einbettung
Vererbung
class X
{
...
};
class Y : public class X
{
...
};


Einbettung
class X
{
...
};
class Y
{
class X var;
...
};
Vererbung hat den Vorteil des Polymorphismus, der Zugriffsregelung
und die Möglichkeit Instanzen der abgeleiteten Klasse wie Objekte der
Basisklasse zu verwenden.
Die Verwendung von Elementobjekten ist dagegen einfacher und
überschaubarer.
Konstruktor



Konstruktoren und Destruktoren werden nicht vererbt. Darum müssen
bei der Objektbildung einer abgeleiteten Klasse die ererbten
Datenelemente vom Konstruktor der jeweiligen Basisklasse erstellt
werden. Die von einer Basisklasse geerbten Elemente bilden in der
abgeleiteten Klasse eine Art Unterobjekt mit eigenem Konstruktoren,
Destruktoren, Zugriffsrechten usw.
Standardkonstruktor
Ist in der Basisklasse der Standardkonstruktor vorhanden, so braucht
sich die abgeleitete Klasse nicht um die Initialisierung der geerbten
Elemente zu kümmern. Der Compiler ruft automatisch den
Konstruktor der abgeleiteten Klasse auf, wenn er ein Objekt der
abgeleiteten Klasse erstellt.
Konstruktor

Spezieller Konstruktor
Mehrfachvererbung


Wird eine Klasse von mehreren Klassen abgeleitet, werden deren
Konstruktoren in der Reihenfolge, in der sie aufgelistet sind
abgearbeitet. Zuletzt wird der Anweisungsteil des Konstruktors der
abgeleiteten Klasse ausgeführt.
class B1 {...};
class B2 {...};
class A : public B1, public B2 {...};
Indirekte Basisklassen

Wird eine Klasse von einer Klasse abgeleitet, die selbst wieder von
einer anderen klasse abgeleitet ist, wird zur Einrichtung des Objektes
der Klasse A zuerst der Konstruktor von B2 aufgerufen, da A von B2
abgeleitet ist. Da B2 aber von B1 abgeleitet ist muß dazu erst der
Konstruktor von B1 aufgerufen werden, damit der Konstruktor von
B2abgearbeitet werden kann. Zuletzt wird der Anweisungsteil des
Konstruktors von A abgearbeitet

class B1 {...};
class B2: public B1 {...};
class A : public B2 {...};
Nicht vererbbare Methoden


Wird eine Klasse aus einer anderen abgeleitet, so erbt diese neue
Klasse, Datenelemente und Methoden.
Es gibt aber Methoden, die nicht mit vererbt werden können.
–
–
–
–

Konstruktor
Destruktor
Zuweisungsoperator
Friend- Deklarationen, sie stellen auch keine wirklichen Elemente dar.
Diese Methoden müssen in der neuen Klasse neu deklariert werden.
Polymorphie





Polymorphie heißt so viel wie „Vielgestaltigkeit“. Der Begriff
Polymorphie ist eng mit der Vererbung verbunden. Er bezeichnet die
Tatsache, das eine Methode in verschiedenen abgeleiteten Klassen
einer Hierarchie unterschiedlich implementiert werden kann.
So ist es möglich, daß verschiedene Klassen gleichlautende Methoden
enthalten, die aber nicht den gleichen Inhalt haben.
Verschiedene Objekte werden gleich behandelt, reagieren aber
unterschiedlich.
Sie können gleich behandelt werden, weil sie zum Teil gleiche
Schnittstellen besitzen (gleichlautende Datenelemente und Methoden).
Beispiel: Paint Programm
Benutzung



Methoden, die in mehreren Klassen benötigt werden, werden in einer
Basisklasse deklariert. In den abgeleiteten Klassen werden sie dann
überschrieben, um eine klassenspezifische Ausführung zu erreichen.
Methoden, die überschrieben werden sollen werden in der Basisklasse
mit dem Schlüsselwort virtual deklariert, um sicher zu stellen, daß
beim Aufruf auch wirklich die pberschriebenen Methoden aufgerufen
werden und nicht die der Basisklasse.
Es ist üblich auch die überschriebenen Methoden in den abgeleiteten
Klassen mit virtual zu kennzeichnen.
Beispiel



Class ZeichenObjekt{
protected:
struct Punkt referenzpunkt;
virtual int zeichne(struct Punkt p){
//zeichne Referenzpunkt an Koordinate
p...}
};
class Rechteck: public ZeichenObjekt{
protected:
struct Punkt ecken[4];
virtual int zeichne (struct Punkt p){
//zeichne Rechteck mit linker unterer Ecke
in p...} };
class Rechteck: public ZeichenObjekt{
protected:
float radius;
virtual int zeichne (struct Punkt p){
//zeichne Kreis mit Mittelpunkt in
p...}
};
Herunterladen