1 / 57

Gliederung

Gliederung. • Ziele von Klassen (Wiederholung) • Phänomene bei der elementaren Vererbung Syntax Überschreiben von Methoden Auflösung von Zirkularität • Einführendes Beispiel: string_Klasse, Woerter_Gross • Beispiel: Person, Mann, Frau. Ziele von Klassen. Schon besprochen:

xanto
Download Presentation

Gliederung

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. Gliederung • • Ziele von Klassen (Wiederholung) • • Phänomene bei der elementaren Vererbung • Syntax • Überschreiben von Methoden • Auflösung von Zirkularität • • Einführendes Beispiel: • string_Klasse, Woerter_Gross • • Beispiel: • Person, Mann, Frau

  2. Ziele von Klassen • Schon besprochen: • Kapselung von Attributen+Methoden (wie struct) • Erweiterte Möglichkeiten gegenüber struct • Überladen von Funktionen • Konstruktoren • Destruktoren • Neu: • Effiziente Wiederverwendbarkeit • dazu:---> Vererbung

  3. Neudefinition der Klasse? • • Bisherige Mittel zum Modellieren von „ähnlichen“ Klassen: • Neudefinition der Klasse • z.B.: Code kann kopiert werden. • • Das ist nicht so gut: • langweilig, • fehleranfällig, • nicht änderungsfreundlich.

  4. Alternative: Vererbung • Seien A und B Klassen. • • A ist Oberklasse von B (B ist Unterklasse von A) • --> B „erbt“ Attribute und Methoden von A, d.h. B „kennt“ Attribute und Methoden von A. (Wie genau, wird im folgenden 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 Instanz von A.

  5. Beispiel: String - Nur Großbuchstaben • • Definiere String als Klasse: • string_Klasse: • Attribute: Zeichenkette, Länge • Methoden: Konstruktor, Destruktor, Lies, Schreibe • • Betrachte „Unterklasse“ • Woerter_Gross: Für Zeichenketten, die Buchstaben nur als Großbuchstaben aufweisen.

  6. string_Klasse 1. Versuch class string_Klasse { private: char * s; int laenge; public: string_Klasse(char *); ~string_Klasse(); bool lies(char *); void schreib(); char * dieKette(); int DieLaenge(); }; Nicht gut: siehe später !

  7. public besagt an dieser Stelle: Übernahme der Zugriffspezifikationen von string_Klasse in die neue Klasse. die Klasse Woerter_gross erbt von der Klasse string_Klasse: Attribute und Methoden von String_Klasse sind in Woerter_Gross verfügbar. Grundansatz Vererbung class Woerter_Gross:public string_Klasse

  8. Grundansatz Vererbung class Woerter_Gross:public string_Klasse { public: Woerter_Gross(char *); void schreib(); };

  9. Verfeinerung des Grundansatzes • 2 Arten des Verbergens: • Geheimnis (auch) vor den Kindern: • A möchte Eigenschaften für sich behalten und nicht beim Vererben weitergeben: • --> Wahl der Zugriffsspezifikation private • Familiengeheimnisse: • Attribute und Methoden werden nur Erben bekannt gemacht, nicht aber Außenstehenden: • --> Wahl der Zugriffsspezifikation protected

  10. „Modifikation“ von string_Klasse class string_Klasse { protected: char * s; int laenge; public: string_Klasse(char *); ~string_Klasse(); bool lies(char *); void schreib(); char * dieKette(); int DieLaenge(); }; steht also für die Erben (und nur für sie) zur Verfügung

  11. Zusammenfassung • Alle als public oder protected zugreifbaren Komponenten sind für die Erben sichtbar. • Die als privatecharakterisierten Komponenten sind in ihrer Sichtbarkeit auf die Klasse selbst beschränkt.

  12. Zugriffsspezifikation private protected public Zugriff nur innerhalb Zugriff nur innerhalb Komponente ist der Klasse der Klasse öffentlich und ihrer Erben zugänglich Klassifikationshierarchie

  13. public besagt hier: Die Zugriffs- spezifikationen für die Komponenten bleiben beim Erben erhalten class Woerter_Gross : public string_Klasse { public: Woerter_Gross(char *); void schreib(); }; Neuer Konstruktor: Heißt ja wie die Klasse

  14. Zugriff auf das Attribut laenge der Oberklasse Konstruktor für Woerter Zugriff auf den Konstruktor der Oberklasse string Woerter_Gross::Woerter_Gross(char * t) : string_Klasse(t) { for (int i=0; i < laenge ; i++) if (islower(s[i])) s[i] = toupper(s[i]); }

  15. Anmerkung • Effekt des Konstruktors (im Beispiel): • Es wird ein Objekt vom Typ Woerter_Gross geschaffen; die Buchstaben der initialisierenden Zeichenkette sind Großbuchstaben. • Der erste Schritt bei der Erzeugung des Objekts besteht im Aufruf des Konstruktors für die Vaterklasse (Syntax!).

  16. Redefinition einer Methode Die Methode schreib wird neu definiert (redefiniert, überschrieben); dabei wird die Methode der Vaterklasse verwendet. void Woerter_Gross::schreib(){ cout << “Ueberschriebene Methode " << "(Achtung)\t\t"; string_Klasse::schreib(); }

  17. /* Woerter_Gross,* Vorlage EED, EINI II, * SS 99, überarbeitet GD 8.4.2000 * demonstriert Vererbung (einfach)*/ #include <iostream.h> // verwendete Funktionsprototypen: void strcpy(char * nach, char * von); int strlen(char * r); bool islower(char c); char toupper(char c);

  18. /* Woerter_Gross, Fortsetzung 1 */ class string_Klasse { protected: char * s; int laenge; public: string_Klasse(char *); ~string_Klasse(); bool lies(char *); void schreib(); char * dieKette(); int DieLaenge(); };

  19. /* Woerter_Gross, Fortsetzung 2 */ string_Klasse::string_Klasse (char *t) { int lgth = strlen(t); s = new char[lgth+1]; strcpy(s, t); laenge = --lgth; // sonst letztes Zeichen '\0' // mitgezählt } string_Klasse::~string_Klasse() { laenge = -1; delete &s; }

  20. /* Woerter_Gross, Fortsetzung 3 */ bool string_Klasse::lies(char * r) { int strlen(char *); if (strlen(r) <= laenge+1) { laenge = strlen(r); strcpy(s, r); return true; } else return false; } void string_Klasse::schreib() { cout << s << endl; }

  21. /* Woerter_Gross, Fortsetzung 4 */ char * string_Klasse::dieKette() { return s;} int string_Klasse::DieLaenge() { return laenge;} class Woerter_Gross: public string_Klasse { public: Woerter_Gross(char *); void schreib(); };

  22. /* Woerter_Gross, Fortsetzung 5 */ Woerter_Gross::Woerter_Gross(char * t): string_Klasse(t) { for (int i=0; i < laenge ; i++) if (islower(s[i])) s[i] = toupper(s[i]); } void Woerter_Gross::schreib(){ cout << "Ueberschriebene Methode " << "(Achtung)\t\t"; string_Klasse::schreib(); }

  23. /* Woerter_Gross, Fortsetzung 6 */ int main() { string_Klasse *s = new string_Klasse ("aBra"); s->schreib(); s->~string_Klasse(); Woerter_Gross * grS = new Woerter_Gross("abra"); grS->schreib(); cout << "Laenge: " <<grS->DieLaenge(); return 0; } Woerter_Gross

  24. /* Woerter_Gross, Fortsetzung 7 */ void strcpy(char * nach, char * von) { while (*nach++ = *von++); } int strlen(char * r) { int f = 0; while (r[f++]); return f; }

  25. /* Woerter_Gross, Fortsetzung 8 */ bool islower(char c) { if (('a' <= c) && (c <= 'z')) return true; else return false; } char toupper(char c) { if (islower(c)) return (c - 'a' + 'A'); else return c; }

  26. Woerter_Gross Ausgabe • aBra • Ueberschriebene Methode (Achtung) ABRA • Laenge: 4

  27. Zusammenfassung • Klasse Woerter_Gross ist Spezialfall der Klasse string_Klasse • (Wörter enthalten nur Großbuchstaben). • Erbende Klasse kann auf alle nicht als private gekennzeichneten Komponenten zugreifen. • Die Zugriffsspezifikation protected wurde eingeführt, um den Zugriff angemessen zu regeln

  28. Zusammenfassung • Ein neuer Konstruktor mußte definiert werden (anderer Name): • Der Konstruktor der Oberklasse kann verwendet werden. • Eine Methode wurde redefiniert • Hierbei wurde auch die gleichnamige Methode des Vaters verwendet. • Die Syntax hierfür wurde eingeführt.

  29. Person Frau Mann Beispiel: Männer und Frauen • Gemeinsame Eigenschaften: • Name (Beschränkung auf Vornamen), • Vater, • Mutter. • --> Oberklasse: Person • Obige Eigenschaften dort formulieren

  30. gemeinsame Eigenschaften gemein- same Methoden class Person { private: string * Vorname; Frau * Mutter; Mann * Vater; public: Person(char *); Person(string *); ~Person(); string * DerVorname(); void SetzeMutter(Frau *); void SetzeVater(Mann *); void Druck(char *); };

  31. Anmerkung • Gemeinsame Eigenschaften private • --> von außen nicht zugreifbar. • Auch von Erben nicht: • sonst als protected vereinbart.

  32. Modellierung der Klasse Frau • Konstruktor (aus Namen und aus Person), • hat Ehemann, • heiratet, • ist Ehefrau von. class Frau: public Person { private: Mann * Ehemann; public: Frau(char *); Frau(Person *); void NimmZumManne(Mann *); Mann * EhefrauVon(); };

  33. Analog: Modellierung Klasse Mann • Konstruktor (aus Namen und aus Person), • hat Ehefrau, • heiratet, • ist Ehemann von. class Mann: public Person { private: Frau * Ehefrau; public: Mann(char *); Mann (Person *); void NimmZurFrau(Frau *); Frau * EhemannVon(); };

  34. Problem: Zirkularität • Person • erfordert die Kenntnis von Frau, Mann, • Mann • erfordert die Kenntnis von Person, Frau, • Frau • erfordert die Kenntnis von Person, Mann. • (Erinnert an forward in Pascal.)

  35. Lösung Deklaration sieht im Programm so aus: hier werden die Namen bekanntgemacht class Mann; class Frau; class Person { ... }; class Frau: public Person { ... }; class Mann: public Person { ... }; Dann erst folgen die Definitionen der Methoden.

  36. Konstruktoren für Klasse Person Konstruktoren für die Klasse sind überladen, einmal Zeichenkette, dann string als Parameter. Person::Person(char * v) { Vorname = new string(v); Vater = NULL; Mutter = NULL; } Person::Person(string * s) { Vorname = s; Vater = NULL; Mutter = NULL; }

  37. Weitere Methoden • Destruktor: • Ruft nur den Destruktor für die Zeichenkette auf Person::~Person() { Vorname->~string(); } • Die anderen Methoden (bis evtl. auf Druck) sollten klar sein. Die Methode Druck druckt den Vornamen aus und ruft ggf. die Druck-Methode für Vater und für Mutter auf.

  38. void Person::Druck(char * s) { cout << s << "(Vorname) " << Vorname->dieKette() << endl; if(Mutter != NULL) { cout << "\nDaten der Mutter:\n"; Mutter->Druck(""); } if(Vater != NULL) { cout << "\nDaten des Vaters:\n "; Vater->Druck(""); } };

  39. Bemerkenswert • Aufrufe • Vater->Druck() und Mutter->Druck()benutzen die Tatsache, daß Vater und Mutter auch vom Typ Person sind. • In den Klassen Mann oder Frau sind keine neuen Methoden Druck vereinbart! • Dies deutet an: • Vererbung erlaubt flexible Modellierung und Programmierung.

  40. Konstruktoren und Methoden für die Klasse Mann Mann::Mann(char * v) :Person(v) { Ehefrau = NULL; } Mann::Mann(Person *p) : Person(p->DerVorname()){ Ehefrau = NULL; } void Mann::NimmtZurFrau(Frau * thisLady) { Ehefrau = thisLady; } Frau * Mann::EhemannVon(){ return Ehefrau; }

  41. Heiratsroutine void Verheirate(Mann * m, Frau * f){ m->NimmZurFrau(f); f->NimmZumManne(m); } Bemerkenswert: steht außerhalb der Klassendefinitionen.

  42. int main() { Mann * Adam = new Mann("Adam"); Frau * Eva = new Frau("Eva"); Mann * Kain = new Mann("Kain"); Kain->SetzeMutter(Eva); Kain->SetzeVater(Adam); Mann * Abel = new Mann("Abel"); Abel->SetzeMutter(Eva); Abel->SetzeVater(Adam); Adam->Druck("Zu Adam: "); Eva->Druck("\nZu Eva:"); Kain->Druck("\n\nAngaben zu Kain:"); Abel->Druck("\n\nAngaben zu Abel:"); Verheirate(Adam, Eva); cout << "\nverheiratet?\n"; Eva->EhefrauVon()-> Druck("\tEva ist verheiratet mit:\n"); Adam->EhemannVon()-> Druck("\tAdam ist verheiratet mit :\n "); return 0;} Mann-Frau

  43. Mann-Frau: Ausgabe • Zu Adam: (Vorname) Adam • Zu Eva: (Vorname) Eva • Angaben zu Kain: (Vorname) Kain • Daten der Mutter: (Vorname) Eva • Daten des Vaters: (Vorname) Adam • Angaben zu Abel: (Vorname) Abel • Daten der Mutter: (Vorname) Eva • Daten des Vaters: (Vorname) Adam • verheiratet? • Eva ist verheiratet mit: • (Vorname) Adam • Adam ist verheiratet mit: • (Vorname) Eva (umformatiert: GD)

  44. // Personen mit Unterklassen // Vorlage EED EINI II, SS 99, prog-27a; // Überarbeitet: GD 14.4.00 // demonstriert Vererbung // #include <iostream.h> #include <stdio.h> #include "clstring.h" class Mann; class Frau; void Verheirate(Mann *, Frau *);

  45. // Personen mit Unterklassen, Fortsetzung 1 class Person { private: stringcl * Vorname; Frau * Mutter; Mann * Vater; public: Person(char *); Person(stringcl *); ~Person(); stringcl * DerVorname(); void SetzeMutter(Frau *); void SetzeVater(Mann *); void Druck(char *); };

  46. // Personen mit Unterklassen, Fortsetzung 2 class Frau: public Person { private: Mann * Ehemann; public: Frau(char *); Frau (Person *); void NimmZumManne(Mann *); Mann * EhefrauVon();}; class Mann: public Person { private: Frau * Ehefrau; public: Mann(char *); Mann (Person *); void NimmZurFrau(Frau *); Frau * EhemannVon();};

  47. // Personen mit Unterklassen, Fortsetzung 3 Person::Person(char * v) { Vorname = new stringcl(v); Vater = NULL; Mutter = NULL;} Person::Person(stringcl * s) { Vorname = s; Vater = NULL; Mutter = NULL;} Person::~Person() { Vorname->~stringcl();} stringcl * Person::DerVorname() { return Vorname;} void Person::SetzeMutter(Frau * Mom) { Mutter = Mom;} void Person::SetzeVater(Mann * Dad) { Vater = Dad;}

  48. // Personen mit Unterklassen, Fortsetzung 4 void Person::Druck(char * s) { cout << s << "\t(Vorname) " << Vorname->dieKette() << endl; if(Mutter != NULL) { cout << "\nDaten der Mutter: " << endl; Mutter->Druck("");} if(Vater != NULL) { cout << "\nDaten des Vaters: " << endl; Vater->Druck("");}}; Frau::Frau(char * v) :Person(v) { Ehemann = NULL;} Frau::Frau(Person *p) :Person(p->DerVorname()){ Ehemann = NULL;}

  49. // Personen mit Unterklassen, Fortsetzung 5 void Frau::NimmZumManne(Mann * erDa) { Ehemann = erDa;} Mann * Frau::EhefrauVon(){ return Ehemann;} Mann::Mann(char * v) :Person(v) { Ehefrau = NULL;} Mann::Mann(Person *p) :Person(p->DerVorname()){ Ehefrau = NULL;} void Mann::NimmZurFrau(Frau * thisLady) { Ehefrau = thisLady;}

More Related