1 / 33

Einführung in die Programmierung Wintersemester 2011/12

Einführung in die Programmierung Wintersemester 2011/12. Prof. Dr. Günter Rudolph Lehrstuhl für Algorithm Engineering Fakultät für Informatik TU Dortmund. Kapitel 10: Vererbung. Ziele von Klassen Schon besprochen: Kapselung von Attributen (wie struct in Programmiersprache C)

damita
Download Presentation

Einführung in die Programmierung Wintersemester 2011/12

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Einführung in die Programmierung Wintersemester 2011/12 Prof. Dr. Günter Rudolph Lehrstuhl für Algorithm Engineering Fakultät für Informatik TU Dortmund

  2. Kapitel 10: Vererbung • Ziele von Klassen • Schon besprochen: • Kapselung von Attributen (wie struct in Programmiersprache C) • Kapselung von klassenspezifischen Funktionen / Methoden • Erweiterte Möglichkeiten gegenüber struct • Konstruktoren / Destruktoren • Überladen von Funktionen (Methoden) und Konstruktoren • Überladen von Operatoren • Neu: • Effiziente Wiederverwendbarkeit • dazu: → Vererbung G. Rudolph: Einführung in die Programmierung ▪ WS 2011/12 2

  3. Vererbung Modellierung von Objekten mit geringen Unterschieden • Bisherige Mittel zum Modellieren von „ähnlichen“ Objekten: • Sei Klasse A bereits definiert (Beispiel: Sparkonten). • Wir wollen jetzt Girokonten modellieren → Klasse B. Ansatz: • Kopiere Code von Klasse A • Umbenennung in Klasse B • Hinzufügen, ändern, entfernen von Attributen und Methoden Probleme: • Aufwändig bei Änderungen (z.B. zusätzlich Freistellungsbetrag für alle Konten) • Fehleranfällig … und langweilig! G. Rudolph: Einführung in die Programmierung ▪ WS 2011/12 3

  4. Vererbung Alternative: Vererbung bzw. Erben • Seien A und B Klassen: • A ist Oberklasse von B bzw. B ist Unterklasse vonA • Wir sagen: Berbt Attribute und Methoden von A d.h. B „kennt“ Attribute und Methoden von A(Grad der Bekanntschaft wird gleich noch detailliert angegeben) • B fügt neue Attribute und Methoden zu denen von A hinzu→ ggf. werden (alte) Methoden neu definiert • Jede Instanz von B ist auch eine Instanz von A G. Rudolph: Einführung in die Programmierung ▪ WS 2011/12 4

  5. extrem „abgespeckte“ Version der Klasse std::string Vererbung Beispiel: Klassen KString und KVersalien • Definiere Klasse KString • Attribute • Zeichenkette • Länge • Methoden • Konstruktor / Destruktor • SetValue, GetValue, Length, Print • Betrachte Unterklasse KVersalien • Für Zeichenketten, die Buchstaben nur als Großbuchstaben aufweisen! G. Rudolph: Einführung in die Programmierung ▪ WS 2011/12 5

  6. Vererbung Klasse KString: 1. Versuch class KString { private: char* mValue; int mLength; public: KString(char *s); bool SetValue(char *s); char *GetValue(); int Length(); void Print(); ~KString(); }; … schon ganz gut, aber … Zugriffsspezifikation private wird Probleme machen! → siehe später! G. Rudolph: Einführung in die Programmierung ▪ WS 2011/12 6

  7. öffentliche Attribute / Methoden private Attribute / Methoden ??? Vererbung Grundansatz Vererbung class KVersalien : public KString { … }; Name der Unterklasse Unterklasse KVersalien erbt von der Oberklasse KString: Attribute und Methoden von KString sind in KVersalien (bedingt) verfügbar! public besagt an dieser Stelle: Übernahme der Zugriffsspezifikationen von der Oberklasse (hier: von KString) G. Rudolph: Einführung in die Programmierung ▪ WS 2011/12 7

  8. private!  public!  public!  Vererbung Grundansatz Vererbung class KVersalien : public KString {public: KVersalien(char *s); // Eigener Konstruktor bool SetValue(char *s); // Überschriebene Methode void Print(); // Überschriebene Methode }; • KVersalien möchte von KString erben: • Attribute mValue und mLength • Methoden GetValue und Length • Destruktor G. Rudolph: Einführung in die Programmierung ▪ WS 2011/12 8

  9. Vererbung Verfeinerung des Grundansatzes • Zwei Arten des Verbergens: • Geheimnis (auch) vor KindernKlasse möchte Attribute und Methoden exklusiv für sich behalten und nicht beim Vererben weitergeben Wahl der Zugriffsspezifikation private • „Familiengeheimnisse“Attribute und Methoden werden nur den Erben (und deren Erben usw.)bekannt gemacht, nicht aber Außenstehenden Wahl der Zugriffsspezifikation protected G. Rudolph: Einführung in die Programmierung ▪ WS 2011/12 9

  10. einzige Veränderung  mValue und mLength sind allen Unterklassen von KString bekannt! Objekte anderer Klassen können nicht darauf zugreifen! Vererbung Klasse KString: 2. Versuch class KString { protected: char* mValue; int mLength; public: KString(char *s); bool SetValue(char *s); char *GetValue(); int Length(); void Print(); ~KString(); }; G. Rudolph: Einführung in die Programmierung ▪ WS 2011/12 10

  11. Zugriffspezifikation private Zugriff nur innerhalb der Klasse protected Zugriff nur innerhalb der Klasse und ihrer Erben public Zugriff sowohl innerhalb der Klasse als auch von außen Vererbung Erste Zusammenfassung • Alle als public oder protected zugreifbaren Komponenten sind für Erben sichtbar. • Die als private charakterisierten Komponenten sind in ihrer Sichtbarkeit auf die Klasse selbst beschränkt. G. Rudolph: Einführung in die Programmierung ▪ WS 2011/12 11

  12. Vererbung Sprachliche Regelung: Der Vorgang des Erzeugens einer Unterklasse aus einer Oberklasse durch Vererbung nennen wir ableiten. Hier: Klasse KVersalien wird von der Klasse KString abgeleitet. sorgt für die soeben zusammengefassten Zugriffsregeln beim Vererben class KVersalien : public KString {public: KVersalien(char *s); // Eigener Konstruktor bool SetValue(char *s); // Überschriebene Methode void Print(); // Überschriebene Methode }; Man sagt auch: public-Ableitung (zur Unterscheidung …) G. Rudolph: Einführung in die Programmierung ▪ WS 2011/12 12

  13. weiteres Ableiten ermöglichen: der Normalfall Spezialfall weiteres Ableiten unterbinden: selten Vererbung Weitere Formen der Ableitung: • public-Ableitung Oberklasse: public → Unterklasse: public Oberklasse: protected → Unterklasse: protected Oberklasse: private → Unterklasse: nicht verfügbar • protected-Ableitung Oberklasse: public → Unterklasse: protected Oberklasse: protected → Unterklasse: protected Oberklasse: private → Unterklasse: nicht verfügbar • private-Ableitung Oberklasse: public → Unterklasse: private Oberklasse: protected → Unterklasse: private Oberklasse: private → Unterklasse: nicht verfügbar G. Rudolph: Einführung in die Programmierung ▪ WS 2011/12 13

  14. Vererbung Implementierung der Klasse KString #include <iostream> #include <cstring> #include "KString.h" using namespace std; KString::KString(char *s) { mLength = strlen(s); // Länge ohne terminale '\0' mValue = new char[mLength+1]; // +1 für '\0'-Zeichen! strcpy(mValue, s); // kopiert auch terminale '\0' } KString::~KString() { delete[] mValue; mLength = -1; } Fortsetzung auf nächster Folie … G. Rudolph: Einführung in die Programmierung ▪ WS 2011/12 14

  15. Vererbung Fortsetzung … int KString::Length() { return mLength; } void KString::Print() { cout << mValue << endl; } char *KString::GetValue() { return mValue; } bool KString::SetValue(char *s) { int length = strlen(s); if (length > mLength) return false; strcpy(mValue, s); mLength = length; return true; } G. Rudolph: Einführung in die Programmierung ▪ WS 2011/12 15

  16. Zuerst wird der Konstruktor der Oberklasse KString aufgerufen Konstruktor der Klasse KVersalien Vererbung Implementierung der abgeleiteten Klasse KVersalien #include <iostream> #include <ctype.h> #include "KVersalien.h" using namespace std; KVersalien::KVersalien(char *s) : KString(s) { for (int i = 0; i < mLength; i++) if (islower(mValue[i])) mValue[i] = toupper(mValue[i]); } • Ablauf: • Zuerst wird Konstruktor von KString aufgerufen,d.h. nach Speicherallokation wird Zeichenkette nach mValue kopiert und mLength wird gesetzt. • Danach wird Code im Konstruktor von KVersalien ausgeführt. G. Rudolph: Einführung in die Programmierung ▪ WS 2011/12 16

  17. expliziter Aufruf der Methode der Oberklasse Zeichenkette mit Elternmethode kopieren, falls genug Platz. Dann Versalien erzeugen. Vererbung Implementierung der abgeleiteten Klasse KVersalien (Fortsetzung) void KVersalien::Print() { cout << "KVersalien::Print -> " << endl; KString::Print(); } bool KVersalien::SetValue(char *s) { if (!KString::SetValue(s)) return false; for (int i = 0; i < mLength; i++) if (islower(mValue[i])) mValue[i] = toupper(mValue[i]); return true; } Methoden Length(),GetValue() und der Destruktor werden von der Eltern- / Oberklasse geerbt !  Implementierung fertig! G. Rudolph: Einführung in die Programmierung ▪ WS 2011/12 17

  18. Vererbung Testumgebung • #include <iostream> • #include "KString.h" • #include "KVersalien.h" • using namespace std; • int main() { • KString *s = new KString("aBraCaDaBra"); • s->Print(); • KVersalien *v = new KVersalien(s->GetValue()); • v->Print(); • s->SetValue("CUl8er"); • s->Print(); • v->SetValue(s->GetValue()); • v->Print(); • delete s; • delete v; • } G. Rudolph: Einführung in die Programmierung ▪ WS 2011/12 18

  19. Vererbung Ausgabe: G. Rudolph: Einführung in die Programmierung ▪ WS 2011/12 19

  20. Vererbung • Sprachregelungen: • Oberklassen werden Elternklassen, manchmal auch Vaterklassen genannt. • Unterklassen sind von Elternklassen abgeleitete Klassen. • Abgeleitete Klassen werden manchmal auch Tochterklassen genannt. • Die Methoden aus Elternklassen können in den abgeiteten Klassenüberschrieben oder redefiniert werden. • Zweite Zusammenfassung • Häufigste Form der Ableitung ist die public-Ableitung: class B:public A {} • Methoden der Elternklassen können benutzt oder überschrieben werden, sofern sie in der Elternklasse public bzw. protected sind. • Überschriebene Methoden der Elternklasse können explizit durch Angabe der Elternklasse aufgerufen werden (Bsp: KString::SetValue). G. Rudolph: Einführung in die Programmierung ▪ WS 2011/12 20

  21. class A vererbt an class B Klassenhierachie: class A class B2 class B1 class B3 class C1 class C2 class C3 class C3 Vererbung Vererbung bisher: (bzw. B erbt von A) hier: einfaches Erben (nur eine Oberklasse) G. Rudolph: Einführung in die Programmierung ▪ WS 2011/12 21

  22. Person Mann Frau Vererbung Beispiel:Einfache Klassenhierachie class Person {private: KString *Vorname; Frau *Mutter; Mann *Vater;public: Person(char *vorname); Person(KString *vorname); char *Name(); void SetzeVater(Mann *m); void SetzeMutter(Frau *f); void Druck(); ~Person(); }; Klasse Person enthält alle Attribute und Methoden, die geschlechtsunspezifisch sind. G. Rudolph: Einführung in die Programmierung ▪ WS 2011/12 22

  23. Person Mann Frau Vererbung Beispiel Klassenhierachie: class Mann : public Person {private: Frau *Ehefrau;public: Mann(char *vn); Mann(Person *p); void NimmZurFrau(Frau *f); Frau *EhemannVon();}; class Frau : public Person {private: Mann *Ehemann;public: Frau(char *vn); Frau(Person *p); void NimmZumMann(Mann *m); Mann *EhefrauVon();}; Die abgeleiteten Klassen Mann und Frau enthalten alle Attribute und Methoden, die geschlechtsspezifisch sind. G. Rudolph: Einführung in die Programmierung ▪ WS 2011/12 23

  24. Person Mann Frau Vererbung Problem: Zirkularität Für Klasse Mann müssen die Klassen Person und Frau bekannt sein! Für Klasse Frau müssen die Klassen Person und Mann bekannt sein! Für Klasse Person müssen die Klassen Mann und Frau bekannt sein! A→ B bedeutet:A wird von B benötigt G. Rudolph: Einführung in die Programmierung ▪ WS 2011/12 24

  25. hier: class Mann;class Frau; class Person { … };class Frau: public Person { … };class Mann: public Person { … }; Vererbung Lösung: Vorwärtsdeklaration(wie bei Funktionen) • bei Funktionen: z.B. void Funktionsname(int x); • bei Klassen: z.B. class Klassenname; G. Rudolph: Einführung in die Programmierung ▪ WS 2011/12 25

  26. Destruktor notwendig wegen Allokation von dynamischem Speicher Person::~Person() { delete Vorname; } Vererbung Zwei Konstruktoren: Person::Person(KString *vn) : Vater(0), Mutter(0) { Vorname = new KString(vn->GetValue()); } Person::Person(char *vn) : Vater(0), Mutter(0) { Vorname = new KString(vn); } G. Rudolph: Einführung in die Programmierung ▪ WS 2011/12 26

  27. Von Person abgeleitete Klassen dürfen Name() nicht überschreiben, sonst ist der Zugriff auf Vorname auch für sie verwehrt! Vererbung char *Person::Name() { return Vorname->GetValue(); } Vorname ist private! Name() ist public! void Person::SetzeMutter(Frau *f) { Mutter = f; } void Person::SetzeVater(Mann *m) { Vater = m; } G. Rudolph: Einführung in die Programmierung ▪ WS 2011/12 27

  28. von Person geerbte Methode Vererbung void Person::Druck(char *s) { cout << s << "Vorname: " << Vorname->GetValue() << endl; if (Mutter != 0) { cout << s << "Mutter: "; Mutter->Druck(""); } if (Vater != 0) { cout << s << "Vater : "; Vater->Druck(""); } } G. Rudolph: Einführung in die Programmierung ▪ WS 2011/12 28

  29. Implementierung der Klasse Mann Implementierung der Klasse Frau Vererbung Mann::Mann(Person *p) : Person(p->Name()), Ehefrau(0) { } Mann::Mann(char *vn) : Person(vn), Ehefrau(0) { } void Mann::NimmZurFrau(Frau *f) { Ehefrau = f; } Frau *Mann::EhemannVon() { return Ehefrau; } Frau::Frau(Person *p) : Person(p->Name()), Ehemann(0) { } Frau::Frau(char *vn) : Person(vn), Ehemann(0) { } void Frau::NimmZumMann(Mann *m) { Ehemann = m; } Mann *Frau::EhefrauVon() { return Ehemann; } G. Rudolph: Einführung in die Programmierung ▪ WS 2011/12 29

  30. Vererbung Hilfsroutinen void Verheirate(Mann *m, Frau *f) { if (m != 0 && f != 0) { m->NimmZurFrau(f); f->NimmZumMann(m); } } Bemerkung: „Schlampige“ Programmierung, weil man vorher noch testen müsste, ob beide Personen ledig sind! void Scheide(Mann *m, Frau *f) { if (m->EhemannVon() == f) { m->NimmZurFrau(0); f->NimmZumMann(0); }} Bemerkung: „Schlampige“ Programmierung, weil … ja, warum? G. Rudolph: Einführung in die Programmierung ▪ WS 2011/12 30

  31. Vererbung Testprogramm int main() { Mann *Anton = new Mann("Anton"); Frau *Bertha = new Frau("Bertha"); Mann *Carl = new Mann("Carl"); Carl->SetzeMutter(Bertha); Carl->SetzeVater(Anton); Frau *Doris = new Frau("Doris"); Doris->SetzeMutter(Bertha); Doris->SetzeVater(Anton); Anton->Druck("A: "); Bertha->Druck("B: "); Carl->Druck("\tC:"); Doris->Druck("\tD:"); Verheirate(Anton, Bertha); Bertha->EhefrauVon()->Druck("B ist Frau von: "); Anton->EhemannVon()->Druck("A ist Mann von: "); delete Doris; delete Carl; delete Bertha; delete Anton; } G. Rudolph: Einführung in die Programmierung ▪ WS 2011/12 31

  32. Vererbung Ausgabe: A: Vorname: Anton B: Vorname: Bertha C:Vorname: Carl C:Mutter: Vorname: Bertha C:Vater : Vorname: Anton D:Vorname: Doris D:Mutter: Vorname: Bertha D:Vater : Vorname: Anton B ist Frau von: Vorname: Anton A ist Mann von: Vorname: Bertha G. Rudolph: Einführung in die Programmierung ▪ WS 2011/12 32

  33. Vererbung Abstrakte Klassen „ … ein paar Bemerkungen vorab …“ hier: • Klasse Person dient nur als „Behälter“ für Gemeinsamkeiten der abgeleiteten Klassen Mann und Frau • Es sollen keine eigenständigen Objekte dieser Klassen instantiiert werden! Hier wäre es jedoch möglich: Person p(“Fred“); → Man kann erzwingen, dass abstrakte Klassen nicht instantiiert werden können! → nächstes Kapitel … (u.a.) G. Rudolph: Einführung in die Programmierung ▪ WS 2011/12 33

More Related