Vererbung

90
Vererbung

description

Vererbung. Das Prinzip der Vererbung im täglichen Leben:. Walter besitzt ein Haus. Walter erbt nun 10000Euro. Also besitzt er insgesamt:. +. 10000. Erblasser. Erbe. In C++:. --->. In C++ darf man einen Erben (abgeleitete Klasse) selbst basteln. abgeleitete Klasse. Basisklasse. - PowerPoint PPT Presentation

Transcript of Vererbung

Page 1: Vererbung

Vererbung

Page 2: Vererbung

Das Prinzip der Vererbung im täglichen

Leben:

Page 3: Vererbung

Walter besitzt ein Haus.

Page 4: Vererbung

Walter erbt nun 10000Euro. Also besitzt er insgesamt:

10000

+

Page 5: Vererbung

In C++:

Erblasser Erbe

--->Basisklasse

--->

abgeleitete Klasse

In C++ darf man einenErben (abgeleitete Klasse)

selbst basteln

Page 6: Vererbung

Statt Basisklasse sagt man auch:Oberklasse, Vaterklasse

Page 7: Vererbung

Statt abgeleiteter Klasse sagt man auch:Unterklasse, Sohnklasse, Subklasse

Page 8: Vererbung

Eine abgeleitete Klasse wird in C++ wie folgt angegeben:

class Ei:public Huhn{

...}

Basisklasse abgeleitete Klasse

wird getrennt durch

Doppelpunkt

Zugriffsart

Page 9: Vererbung

Die abgeleitete Klasse (kurz: Ableitung) besitzt

automatisch alle Member (Ausnahme: Konstruktor)

der Basisklasse.

Page 10: Vererbung

Beispiel:

Page 11: Vererbung

Von einem Flachdachhaus wird ein Modell

(Draufsicht) erstellt:

Page 12: Vererbung

Der Einfachheit halber wird nur die Grundfläche (ohne Zimmer, usw.) des Hauses abgebildet.Aufgabe:Realsieren Sie die Klasse Modell in C++.

Page 13: Vererbung

class Modell{ private: double l; double b;

public: Modell(double ll, double bb); void setL(double ll); void setB(double bb); double getL(); double getB(); double getFlaeche();}

Page 14: Vererbung

Modell::Modell(double ll, double bb){l = ll;b = bb;

}

void Modell::setL(double ll){l = ll;

}

void Modell::setB(double bb){b = bb;

}

Page 15: Vererbung

double Modell::getL(){return(l);

}

double Modell::getB(){return(b);

}

double Modell::getFlaeche(){return(l*b);

}

Page 16: Vererbung

Jetzt soll ein “genaueres“ Modell des Flachdachhauses erstellt werden: Modell aus Styropor (oder Ton). Aufgabe:Realsieren Sie in C++ die Klasse Gmodell.

Page 17: Vererbung

Wie kann man sich dabei Schreibarbeit sparen ? Wie kann man Softwareteile dabei wiederverwenden ?

Indem man die Vererbung benutzt.

Page 18: Vererbung

Welche Member der Klasse Modell kann man übernehmen (erben) ?

Welche Member kommen neu dazu ?

Page 19: Vererbung

class Modell{ private: double l; double b;

public: Modell(double ll, double bb); void setL(double ll); void setB(double bb); double getL(); double getB(); double getFlaeche();}

Alle außer dem Konstruktor

Welche Member werden vererbt ?

Welche Member müssen neu dazu ?

Page 20: Vererbung

class Gmodell { private: double l;double l; double b;double b;

public:

void setL(double ll);void setL(double ll); void setB(double bb);void setB(double bb); double getL();double getL(); double getB();double getB(); double getFlaeche();double getFlaeche();

}

double h;

double getVolumen();

Die reliefförmig dargestellten Member werden geerbt.

Die rot dargestellten Member kommen neu dazu.

Wie wird eine Vererbung erreicht ?

:public Modell

void setH(double hh);double getH();

Gmodell(double ll, double bb, double hh);

Page 21: Vererbung

Also sieht die Klasse folgendermassen aus:

Page 22: Vererbung

class Gmodell:public Modell{ private: double h;

public: Gmodell(double ll, double bb, double hh); void setH(double hh); double getH(); double getVolumen();}

Die Methoden müssen noch außerhalb der Klassen implementiert werden.

Page 23: Vererbung

Realisieren Sie die Methoden in C++

Page 24: Vererbung

void Gmodell::setH(double hh){h = hh;

}

double Gmodell::getH(){return(h);

}

double Gmodell::getVolumen(){return(getFlaeche()*h);

}

Diese Methode wird von der Klasse Modell vererbt.

Page 25: Vererbung

double Gmodell::getVolumen(){return(b*l*h);

}

Warum ist diese Lösung falsch ?

Es gibt Probleme mit dem Zugriffschutz (l und b sind private).Näheres dazu siehe später.

Page 26: Vererbung

Gmodell::Gmodell(double ll, double bb, double hh): Modell(ll,bb){ setH(hh);}Da die Klasse Gmodell von der Klasse Modell erbt, muß beim Anlegen eines Objekts der Klasse Gmodell auch der Konstruktor der Klasse Modell aufgerufen werden.

Wird dies nicht gemacht, dann wird automatisch (ohne Zutun des Programmierers) der Standardkonstruktor der Klasse Modell aufgerufen.

Was passiert, wenn der Standardkonstruktor nicht existiert ?

Dann wird dieser automatisch vom Compiler angelegt, außer ....

es gibt einen Konstruktor mit (1, 2, 3, ...) Parametern.Dann liefert der Compiler eine Fehlermeldung.

Page 27: Vererbung

Beispiel für die Benutzung der o.g. Klassen in einem

Hauptprogramm:

Page 28: Vererbung

int main(){ Modell m(10,20); Gmodell g(2,3,4); double a,b,c, f, v; a = m.getL(); b = m.getB(); c = m.getH(); f = m.getFlaeche(); v = m.getVolumen(); a = g.getL(); b = g.getB(); c = g.getH(); f = g.getFlaeche(); v = g.getVolumen(); return 0;}

// a=10// b=20// syntaktisch falsch

// f=200

// a=2// b=3// c=4// f=6 // v=24

// synt. falsch

Page 29: Vererbung

Verdeckte Member

Page 30: Vererbung

class Gmodell:public Modell{ private: double h;

public: Gmodell(double ll, double bb, double hh); void setH(double hh); double getH(); double getVolumen(); double getFlaeche();}

Alles gleich wie vorher außer, daß eine Methode gleichen Namens wie in der Basisklasse existiert, die die Oberfläche des Modells (Quaders) berechnet. Wie muss sie implementiert werden ?

Page 31: Vererbung

double Gmodell::getFlaeche(){ return(2*(getL()*getB()+getL()*h +getB()*h)); }

double Gmodell::getFlaeche(){ return(2*(l*b+l*h+b*h));}

Warum ist diese Lösung falsch ?

Es gibt Probleme mit dem Zugriffschutz (l und b sind private).Näheres dazu siehe später.

Page 32: Vererbung

int main(){ Gmodell g(2,3,4); double f; f = g.getFlaeche();

return 0;

}

// f=6

Es wird auf die Methode der Unterklasse und nicht der Oberklasse zugegriffen, weil die Methode der Oberklasse durch die Methode der Unterklasse verdeckt wird.

Mit Angabe der Klasse und des sogenannten Scope Operators :: kann man auf die verdeckten Mitglieder zugreifen.

f = g.Modell::getFlaeche();

// f=52

Von welcher Klasse wird diese Methode aufgerufen ?

Page 33: Vererbung

Darstellung der Vererbung durch UML

Page 34: Vererbung

Basisklasse...

...

Subklasse...

...

Attribute

Methoden

Attribute

Methoden

Pfeil bedeutet: erbt von

Analog zum Zugriffsschutz +und - bedeutet # :Methode ist protected

Page 35: Vererbung

Aufgabe:

Stellen Sie die Klassen Modell, Gmodell und ihre Vererbungshierarchie in UML dar.

Page 36: Vererbung

Modell - l: double - b: double + Modell(double ll, double bb) + setL(double ll): void + setB(double bb): void + getL():double + getB():double + getFlaeche():double

Gmodell - h: double + Gmodell(double ll, double bb, double hh) + setH(double hh): void + getH():double + getVolumen():double

Statt dem Zugriffschutz + oder - kann auch der Zugriffschutz # (siehe später) benutzt werden.

Page 37: Vererbung

Zugriffschutz (Zugriffsberechtigung) bei

Klassen

Page 38: Vererbung

Bedeutung der Zugriffsarten:

Page 39: Vererbung

Zugriff innerhalb einer Klasse bedeutet den Zugriff auf ein Member von innerhalb einer Methode der Klasse.

Beispiel:

void Modell::setL(double ll){ l = ll;}

Zugriff auf das Member setL

Page 40: Vererbung

Zugriff außerhalb einer Klasse bedeutet den Zugriff auf ein Member von einem Objekt mit Hilfe des Punkts .

Beispiel:int main{ Modell m(2,8); m.setL(5); return 0;}

Zugriff auf das Member setL

Page 41: Vererbung

Zugriffschutz (Zugriffsberechtigung) bei Klassen ohne Vererbung

Page 42: Vererbung

Beispiel:

Page 43: Vererbung

class Waisenkind{ private: int priWK;

protected: int proWK;

public: int pubWK;

void f_WK(){priWK=1; proWK; pubWK=3;

}};

int main(){ Waisenkind myWK; myWK.f_WK(); myWK.priWK=10; myWK.proWK=11; myWK.pubWK=12; return 0;}

Wo sind die Zugriffe ? Sind diese außerhalb/innerhalb ? Sind sie möglich ?

Zugriff außerhalb, möglich

Zugriff innerhalb, möglich

Zugriff innerhalb, möglich

Zugriff innerhalb, möglich

Zugriff außerhalb, unmöglich

Zugriff außerhalb, unmöglich

Zugriff außerhalb, möglich

Page 44: Vererbung

class Waisenkind{ private: int priWK;

protected: int proWK;

public: int pubWK;

void f_WK(){priWK=1; proWK; pubWK=3;

}};

int main(){ Waisenkind myWK; myWK.f_WK(); myWK.priWK=10; myWK.proWK=11; myWK.pubWK=12; return 0;}

Welche Regel läßt sich daraus ableiten ?

Zugriff innerhalb ist auf private, protected und public Member möglich. Zugriff außerhalb ist nur auf public Member möglich.

Page 45: Vererbung

Zugriffschutz (Zugriffsberechtigung) bei

Klassen mit Vererbung

Page 46: Vererbung

Auf die nicht vererbten Member einer Klasse gilt die gleiche Regel wie vorher:Zugriff innerhalb ist auf private, protected und public Member möglich. Zugriff außerhalb ist nur auf public Member möglich.

Page 47: Vererbung

Das Problem ist nur:Wie ist der Zugriffschutz (Zugriffsberechtigung) auf die vererbten Member einer Klasse geregelt ?

Page 48: Vererbung

Zugriff auf die vererbten Member einer Klasse:

Page 49: Vererbung

Aus Platzgründen muss im Folgenden auf die Trennung

von Deklaration und Implementierung der Methoden verzichtet

werden.

Page 50: Vererbung

Beispiel:

Page 51: Vererbung

class Mutter{ private: int priM;

protected: int proM;

public: int pubM;};

Zugriffsmanipulation der Member in der Basisklasse und ...

Page 52: Vererbung

class Kind1:private Mutter{ private: void prifK(){ priM=11; proM=12; pubM=13; }

protected: void profK(){ priM=14; proM=15; pubM=16; }

public: void pubfK(){ priM=17; proM=18; pubM=19; }};

... Zugriffsmanipulation (der gesamten Basisklasse) bei der Vererbung der Klasse bestimmen die Zugriffsberechtigung:

Sind die Zugriffe auf die rotgedruckten Member in der Basisklasse möglich ?

protected

public

Page 53: Vererbung

Insgesamt bestimmen also die "Schalter" Zugriffsmanipulation der Basisklasse und Zugriffsmanipulation der Member der Basisklasse die resultierende Zugriffsberechtigung.

Page 54: Vererbung

private-Member:Zugriff nur von innerhalb der Klasse möglich

protected -Member:Zugriff von innerhalb der Klasse möglichZugriff von innerhalb einer abgeleiteten Klasse möglich

public -Member :Zugriff von innerhalb der Klasse möglichZugriff von innerhalb einer abgeleiteten Klasse möglichZugriff von außerhalb einer Klasse aus möglich

Page 55: Vererbung

int main(){ Kind1 k1; k1.prifK(); k1.profK(); k1.pubfK(); k1.priM=105; k1.proM=109; k1.pubM=113; return 0;}

Bei welchen Anweisungen oben können Sie jetzt schon entscheiden, ob die Zugriffe erlaubt sind oder nicht ? Bei welchen können Sie noch nicht entscheiden ?

Um welche Zugriffe handelt es sich (innerhalb / außerhalb) ?

Zugriff von außerhalb auf ein nicht vererbtes private Member: nicht erlaubt

Zugriff von außerhalb auf ein nicht vererbtes protected Member: nicht erlaubt

Zugriff von außerhalb auf ein nicht vererbtes public Member: erlaubt

Die restlichen Zugriffe von außerhalb betreffen vererbte Member: bis jetzt noch nicht entscheidbar, muss noch geregelt werden...

Page 56: Vererbung

private protected public

privatekein

Zugriffkein

Zugriffkein

Zugriff

protected private protected protected

public private protected public

Zugriffsberechtigung von der abgeleiteten Klasse auf die vererbten Member der Basisklasse :

Man sieht: Die Zugriffsberechtigung der Basisklasse kann durch die Klassenspezifikation vermindert, aber nicht vergrößert werden.

Member in Basisklasse

Vererbung Basisklasse

Page 57: Vererbung

Sinn:Member von Klassen, die

z.B. für die Gestaltung einer grafischen Oberfläche vom

System zur Verfügung gestellt werden, sollen nicht durch eine Vererbung, die

ein Programmierer realisiert, vergrößert werden können.

Page 58: Vererbung

Für die resultierende Zugriffsberechtigung für die vererbten Member gilt die gleiche Regel wie vorher:

Page 59: Vererbung

Zugriff innerhalb ist auf private, protected und public Member möglich. Zugriff außerhalb ist nur auf public Member möglich. Wobei private, protected und public aus der vorigen Tabelle ermittelt werden müssen !!

Page 60: Vererbung

Damit gilt dann für den Zugriff von der abgeleiteten

Klasse aus:

Page 61: Vererbung

private protected public

private - - -

protected + + +

public + + +

+ bedeutet: Zugriff möglich- bedeutet: Kein Zugriff möglich (Compiler)

Member in Basisklasse

Vererbung Basisklasse

Page 62: Vererbung

Damit gilt dann für den Zugriff von außerhalb:

Page 63: Vererbung

private protected public

private - - -

protected - - -

public - - +

Member in Basisklasse

Vererbung Basisklasse

Page 64: Vererbung

Gesamtergebnis:

R1) Zugriff auf ein vererbtes Member:a) Regel anwenden

R2) Zugriff auf ein nicht vererbtes Member:a) Resultierende Zugriffsberechtigung aus Tabelle ermittelnb) Regel anwenden

Page 65: Vererbung

Zurück zur vorigen Aufgabe.

Welche Zugriffe sind möglich und warum ?(kein Zugriff bedeutet:

Fehlermeldung des Compilers)

Page 66: Vererbung

class Mutter{ private: int priM;

protected: int proM;

public: int pubM;};

Page 67: Vererbung

class Kind1:private Mutter{ private: void prifK(){ priM=11; proM=12; pubM=13; }

protected: void profK(){ priM=14; proM=15; pubM=16; }

public: void pubfK(){ priM=17; proM=18; pubM=19; }};

private + private = kein Zugriff (R2)

protected + private = private (R2)

public + private = private (R2)

private + private = kein Zugriff (R2)

protected + private = private (R2)

public + private = private (R2)

private + private = kein Zugriff (R2)

protected + private = private (R2)

public + private = private (R2)

Page 68: Vererbung

int main(){ Kind1 k1; k1.prifK(); k1.profK(); k1.pubfK(); k1.priM=105; k1.proM=109; k1.pubM=113; return 0;}

Voraussetzungen: In der letzten Folie werden die Anweisungen, die keinen Zugriff verursachen und eine Compilermeldung bringen, entfernt.

no: private (R1)

no: protected (R1)

yes: public (R1)

no bedeutet : kein Zugriff möglich

yes bedeutet : Zugriff möglich

no: private + private = kein Zugriff (R2)

no: protected + private = private (R2)

no: public + private = private (R2)

Page 69: Vererbung

Der Klassenzugriffschutz wird von private auf protected geändert.Was passiert ?

Page 70: Vererbung

class Kind2:private Mutter{ private: void prifK(){ priM=11; proM=12; pubM=13; }

protected: void profK(){ priM=14; proM=15; pubM=16; }

public: void pubfK(){ priM=17; proM=18; pubM=19; }};

Page 71: Vererbung

class Kind2: Mutter{ private: void prifK(){ priM=11; proM=12; pubM=13; }

protected: void profK(){ priM=14; proM=15; pubM=16; }

public: void pubfK(){ priM=17; proM=18; pubM=19; }};

Page 72: Vererbung

class Kind2: Mutter{ private: void prifK(){ priM=11; proM=12; pubM=13; }

protected: void profk(){ priM=14; proM=15; pubM=16; }

public: void pubfK(){ priM=17; proM=18; pubM=19; }};

protectedprivate + protected = kein Zugriff (R2)

protected + protected = protected (R2)

public + protected = protected (R2)

private + protected = kein Zugriff (R2)

protected + protected = protected (R2)

public + protected = protected (R2)

private + protected = kein Zugriff (R2)

protected + protected = protected (R2)

public + protected = protected (R2)

Page 73: Vererbung

int main(){ Kind2 k2; k2.prifK(); k2.profK(); k2.pubfK(); k2.priM=105; k2.proM=109; k2.pubM=113; return 0;}

Voraussetzungen: In der letzten Folie werden die Anweisungen, die keinen Zugriff verursachen und eine Compilermeldung bringen, entfernt.

no: private (R1)

no: protected (R1)

yes: public (R1)

no: private + protected = kein Zugriff (R2)

no bedeutet : kein Zugriff möglich

yes bedeutet : Zugriff möglich

no: protected + protected = protected (R2)

no: public + protected = protected (R2)

Page 74: Vererbung

Der Klassenzugriffschutz wird von protected auf public geändert.Was passiert ?

Page 75: Vererbung

class Kind3:protected Mutter{ private: void prifK(){ priM=11; proM=12; pubM=13; }

protected: void profK(){ priM=14; proM=15; pubM=16; }

public: void pubfK(){ priM=17; proM=18; pubM=19; }};

Page 76: Vererbung

class Kind3: Mutter{ private: void prifK(){ priM=11; proM=12; pubM=13; }

protected: void profK(){ priM=14; proM=15; pubM=16; }

public: void pubfK(){ priM=17; proM=18; pubM=19; }};

Page 77: Vererbung

class Kind3: Mutter{ private: void prifK(){ priM=11; proM=12; pubM=13; }

protected: void profK(){ priM=14; proM=15; pubM=16; }

public: void pubfk(){ priM=17; proM=18; pubM=19; }};

publicprivate + public = kein Zugriff (R2)

protected + public = protected (R2)

public + public = public (R2)

private + public = kein Zugriff (R2)

protected + public = protected (R2)

public + public = public (R2)

private + public = kein Zugriff (R2)

protected + public = protected (R2)

public + public = public (R2)

Page 78: Vererbung

int main(){ Kind3 k3; k3.prifK(); k3.profK(); k3.pubfK(); k3.priM=105; k3.proM=109; k3.pubM=113; return 0;}

Voraussetzungen: In der letzten Folie werden die Anweisungen, die keinen Zugriff verursachen und eine Compilermeldung bringen, entfernt.

no: private (R1)

no: protected (R1)

yes: public (R1)

no bedeutet : kein Zugriff möglich

yes bedeutet : Zugriff möglich

no: private + public = kein Zugriff (R2)

no: protected + public = protected (R2)

yes: public + public = public (R2)

Page 79: Vererbung

Konstruktoren, Destruktoren bei der Vererbung

Page 80: Vererbung

Beispiel:

Page 81: Vererbung

class BasisKlasse{ public: BasisKlasse(int i); ~BasisKlasse();}; BasisKlasse::BasisKlasse(int i){ cout << "Aufruf Konstr. BK \n");}; BasisKlasse::~BasisKlasse(){ cout << "Aufruf Destr. BK \n");};

Page 82: Vererbung

class SubKlasse:public BasisKlasse{

public: SubKlasse(int i); ~SubKlasse();}; SubKlasse::SubKlasse(int i): BasisKlasse(i){ cout << "Aufruf Konstr. SK \n");};

SubKlasse::~SubKlasse(){ cout << "Aufruf Destr. SK \n");};

Page 83: Vererbung

// Welche Ausgaben werden auf dem // Bildschirm erzeugt ?

int main(){ SubKlasse s(1); return 0;}

Page 84: Vererbung

Aufruf Konst. BKAufruf Konst. SKAufruf Destr. SKAufruf Destr. BK

Es gilt des weiteren:

Page 85: Vererbung

Wenn der Konstruktor der Subklasse nicht (weil es der Programmierer vergessen hat zu implementieren) einen Konstruktor der Basisklasse aufruft, dann ruft er automatisch den Standardkonstruktor der Basisklasse auf.

Page 86: Vererbung

Der Destruktor in der Subklasse ruft automatisch den Destruktor der Basisklasse auf.Wenn der Destruktor der Subklasse nicht implementiert wird, wird er automatisch vom Compiler erzeugt. Dieser automatisch erzeugte Destruktor ruft dann auch den Destruktor der Basisklasse auf.

Page 87: Vererbung

Wann soll man eine Vererbung sinnvoll

einsetzen ?

Page 88: Vererbung

wenn die folgende Beziehung besteht:

Subklasse "ist ein(e)"

Basisklasse.

Page 89: Vererbung

Beispiele der Vererbung:Ein LKW ist ein FahrzeugEine Katze ist ein TierEine Tulpe ist eine Pflanze

abgeleitete Klasse

Basisklasse

Page 90: Vererbung

Der Prozeß, um von einer Basisklasse durch Detaillierung und Konkretiserung zu einer Subklasse zu kommen, nennt man Spezialisierung.

Der Prozeß, um von einer Subklasse durch Verallgemeinerung und Abstraktion zur Basisklasse zu kommen, nennt man Generalisierung.