Einfhrung in die Programmierung Wintersemester 201718 Prof Dr

  • Slides: 27
Download presentation
Einführung in die Programmierung Wintersemester 2017/18 Prof. Dr. Günter Rudolph Lehrstuhl für Algorithm Engineering

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

Kapitel 11: Virtuelle Methoden Kapitel 11 Vererbung bisher: ● Definition von Klassen basierend auf

Kapitel 11: Virtuelle Methoden Kapitel 11 Vererbung bisher: ● Definition von Klassen basierend auf anderen Klassen - Übernahme (erben) von Attributen und Methoden - Methoden können überschrieben werden Bindung der Methoden an Objekte geschieht zur Übersetzungszeit! jetzt: Technik zur Bindung von Methoden an Objekte zur Laufzeit! → dynamische Bindung: Polymorphismus G. Rudolph: Einführung in die Programmierung ▪ WS 2017/18 2

Virtuelle Methoden Kapitel 11 Klassenhierarchie Früchte Attribut: die. Frucht Methode: Druck() Erbse Hülsenfrüchte Bohne

Virtuelle Methoden Kapitel 11 Klassenhierarchie Früchte Attribut: die. Frucht Methode: Druck() Erbse Hülsenfrüchte Bohne Methode: Druck() … Folgendes Beispiel: konventionelle Version vs. Version mit virtuellen Methoden Obst Methode: Druck() Südfrüchte Methode: Druck() Apfel Birne … Anana s Banan e … G. Rudolph: Einführung in die Programmierung ▪ WS 2017/18 3

Virtuelle Methoden Kapitel 11 Konventionelle Version class Frucht { protected: string die. Frucht; public:

Virtuelle Methoden Kapitel 11 Konventionelle Version class Frucht { protected: string die. Frucht; public: Frucht(char *name); Frucht(string &name); void Druck(); }; Frucht. h Frucht: : Frucht(char *name) : die. Frucht(name) { } Frucht: : Frucht(string &name) : die. Frucht(name) { } void Frucht: : Druck() { cout << “(F) “ << die. Frucht << endl; } Frucht. cpp G. Rudolph: Einführung in die Programmierung ▪ WS 2017/18 4

Virtuelle Methoden Kapitel 11 Konventionelle Version class HFrucht : public Frucht { public: HFrucht(char

Virtuelle Methoden Kapitel 11 Konventionelle Version class HFrucht : public Frucht { public: HFrucht(char *name); void Druck(); }; Unterklasse von Frucht class Obst : public Frucht { public: Obst(char *name); void Druck(); }; Unterklasse von Frucht class SFrucht : public Obst { public: SFrucht(char *name); void Druck(); }; Unterklasse von Obst G. Rudolph: Einführung in die Programmierung ▪ WS 2017/18 5

Virtuelle Methoden Kapitel 11 Konventionelle Version HFrucht: : HFrucht(char *name) : Frucht(name) { }

Virtuelle Methoden Kapitel 11 Konventionelle Version HFrucht: : HFrucht(char *name) : Frucht(name) { } void HFrucht: : Druck() { cout << "(H) " << die. Frucht << endl; } Obst: : Obst(char *name) : Frucht(name) { } void Obst: : Druck() { cout << "(O) " << die. Frucht << endl; } SFrucht: : SFrucht(char *name) : Obst(name) { } void SFrucht: : Druck() { cout << "(S) " << die. Frucht << endl; } G. Rudolph: Einführung in die Programmierung ▪ WS 2017/18 6

Virtuelle Methoden Kapitel 11 Konventionelle Version: Testprogramm int main() { Frucht *ruebe = new

Virtuelle Methoden Kapitel 11 Konventionelle Version: Testprogramm int main() { Frucht *ruebe = new Frucht("Ruebe"); ruebe->Druck(); HFrucht *erbse = new HFrucht("Erbse"); erbse->Druck(); 1. Teil Obst *apfel = new Obst("Apfel"); apfel->Druck(); SFrucht *banane = new SFrucht("Banane"); banane->Druck(); Ausgabe: (F) (H) (O) (S) Ruebe Erbse Apfel Banane G. Rudolph: Einführung in die Programmierung ▪ WS 2017/18 7

Virtuelle Methoden Kapitel 11 Konventionelle Version: Testprogramm Frucht *f = new Frucht("Frucht"); f->Druck(); f

Virtuelle Methoden Kapitel 11 Konventionelle Version: Testprogramm Frucht *f = new Frucht("Frucht"); f->Druck(); f = apfel; // jedes Obst ist auch Frucht f->Druck(); 2. Teil Obst *o = new Obst("Obst"); o->Druck(); o = banane; // Suedfrucht ist auch Obst o->Druck(); } Ausgabe: (F) (O) Frucht Apfel Obst Banane G. Rudolph: Einführung in die Programmierung ▪ WS 2017/18 8

Virtuelle Methoden Kapitel 11 Merke: ● Zuweisungen sind entlang der Vererbungshierarchie möglich → Objekt

Virtuelle Methoden Kapitel 11 Merke: ● Zuweisungen sind entlang der Vererbungshierarchie möglich → Objekt kann einem Objekt seiner Oberklasse zugewiesen werden ● Methoden sind (hier) statisch an Objekt gebunden → zur Übersetzungszeit bekannte Methode wird ausgeführt → Zuweisung eines Objekts einer abgeleiteten Klasse führt nicht zur Übernahme der überschriebenen Methoden der Unterklasse Wenn man das haben möchte, dann müssten die Methoden der Unterklasse zur Laufzeit (bei der Zuweisung) an das Objekt gebunden werden! → dynamische Bindung! G. Rudolph: Einführung in die Programmierung ▪ WS 2017/18 9

Virtuelle Methoden Kapitel 11 Statische Methodenbindung Frucht *f; Frucht: : Druck() Verwendung der Methode,

Virtuelle Methoden Kapitel 11 Statische Methodenbindung Frucht *f; Frucht: : Druck() Verwendung der Methode, die zur Definitionszeit für Objekt f bekannt! Zuweisung von apfel der Klasse Obst an f: f = apfel; Datenkopie! f->Druck(); G. Rudolph: Einführung in die Programmierung ▪ WS 2017/18 10

Virtuelle Methoden Kapitel 11 Dynamische Methodenbindung Frucht *f; Obst: : Druck() Verwendung der Methode,

Virtuelle Methoden Kapitel 11 Dynamische Methodenbindung Frucht *f; Obst: : Druck() Verwendung der Methode, die zur Laufzeit für Objekt f bekannt! Zuweisung von apfel der Klasse Obst an f: f = apfel; Datenkopie! „Typkopie“! f->Druck(); Objekt f wird markiert als Instanz von Obst G. Rudolph: Einführung in die Programmierung ▪ WS 2017/18 11

Virtuelle Methoden Kapitel 11 Virtuelle Methoden ● sind Methoden, die zur Laufzeit (also dynamisch)

Virtuelle Methoden Kapitel 11 Virtuelle Methoden ● sind Methoden, die zur Laufzeit (also dynamisch) gebunden werden sollen; ● werden in der Oberklasse durch Schlüsselwort virtual gekennzeichnet. Wird eine virtuelle Methode in einer abgeleiteten Klasse überschrieben, so wird die Methode ausgewählt, die sich aus dem Typ des Objekts zur Laufzeit ergibt! G. Rudolph: Einführung in die Programmierung ▪ WS 2017/18 12

Virtuelle Methoden Kapitel 11 Version mit virtuellen Funktionen class Frucht { protected: string die.

Virtuelle Methoden Kapitel 11 Version mit virtuellen Funktionen class Frucht { protected: string die. Frucht; public: Frucht(char *name); Frucht(string &name); Ansonsten keine Änderungen im Code der konventionellen Version! virtual void Druck(); }; Kennzeichnung als virtuelle Methode: Instanzen von abgeleiteten Klassen suchen dynamisch die entsprechende Methode aus. G. Rudolph: Einführung in die Programmierung ▪ WS 2017/18 13

Virtuelle Methoden Kapitel 11 Konsequenzen: Testprogramm mit virtuellen Methoden (nur 2. Teil) Frucht *f

Virtuelle Methoden Kapitel 11 Konsequenzen: Testprogramm mit virtuellen Methoden (nur 2. Teil) Frucht *f = new Frucht("Frucht"); f->Druck(); f = apfel; // jedes Obst ist auch Frucht f->Druck(); 2. Teil Obst *o = new Obst("Obst"); o->Druck(); o = banane; // Suedfrucht ist auch Obst o->Druck(); } Ausgabe: (F) Frucht (O) Apfel (dyn. ) (O) Obst (S) Banane Ausgabe: (F) Frucht (F) Apfel (stat. ) (O) Obst (O) Banane G. Rudolph: Einführung in die Programmierung ▪ WS 2017/18 14

Virtuelle Methoden Kapitel 11 Achtung: Zeiger notwendig! SFrucht *kiwi = new SFrucht(“kiwi“); kiwi->Druck(); Obst

Virtuelle Methoden Kapitel 11 Achtung: Zeiger notwendig! SFrucht *kiwi = new SFrucht(“kiwi“); kiwi->Druck(); Obst obst(“Obst statisch“); obst. Druck(); obst = *kiwi; nur Daten-, keine Typkopie obst. Druck(); wie statische Bindung Ausgabe: (dyn. ) (S) kiwi (O) Obst statisch (O) kiwi dynamische Bindung funktioniert nur mit Zeigern oder Referenzen! G. Rudolph: Einführung in die Programmierung ▪ WS 2017/18 15

Virtuelle Methoden Kapitel 11 Anmerkung: Als virtuell gekennzeichnete Methode muss nicht in jeder abgeleiteten

Virtuelle Methoden Kapitel 11 Anmerkung: Als virtuell gekennzeichnete Methode muss nicht in jeder abgeleiteten Klasse redefiniert / überschrieben werden! Methode für Laufzeittyp vorhanden? ja nein in Vererbungsbaum aufsteigen: Methode in Oberklasse vorhanden? ja verwende Methode nein G. Rudolph: Einführung in die Programmierung ▪ WS 2017/18 16

Virtuelle Methoden Kapitel 11 Beispiel class X { public: virtual void Druck(); }; void

Virtuelle Methoden Kapitel 11 Beispiel class X { public: virtual void Druck(); }; void X: : Druck() { class Y : public X { public: void Druck(); }; void Y: : Druck() { cout << “X“; } cout << “Y“; } class Z : public Y { }; int main() { X *p[4] = { new X, new Y, new X, new Z }; for (int i = 0; i < 4; i++) p[i]->Druck(); return 0; } Ausgabe: XYXY dynamische Bindung! G. Rudolph: Einführung in die Programmierung ▪ WS 2017/18 17

Virtuelle Methoden Kapitel 11 Beispiel (Fortsetzung) class X { public: virtual void Druck(); };

Virtuelle Methoden Kapitel 11 Beispiel (Fortsetzung) class X { public: virtual void Druck(); }; void X: : Druck() { class Y : public X { public: void Druck(); }; void Y: : Druck() { cout << “X“; } cout << “Y“; } class Z : public Y { }; int main() { X *p[4] = { new X, new Y, new X, new Z }; for (int i = 0; i < 4; i++) p[i]->Druck(); return 0; } Ausgabe: XXXX statische Bindung! G. Rudolph: Einführung in die Programmierung ▪ WS 2017/18 18

Virtuelle Methoden Kapitel 11 Rein virtuelle Methoden Annahme: Wir wollen erzwingen, dass jeder Programmierer,

Virtuelle Methoden Kapitel 11 Rein virtuelle Methoden Annahme: Wir wollen erzwingen, dass jeder Programmierer, der von unserer Basisklasse eine neue Klasse ableitet, eine bestimmte Methode implementiert bzw. bereitstellt! Realisierung in C++ 1. Die Methode wird als virtuell deklariert. 2. Bei der Deklaration wird hinter der Signatur =0 eingefügt. 3. Die Methode bleibt in dieser Klasse undefiniert. Die Erben müssen die Definition der Methode nachholen! G. Rudolph: Einführung in die Programmierung ▪ WS 2017/18 19

Virtuelle Methoden Kapitel 11 Rein virtuelle Methoden / abstrakte Klassen aus dem C++ Standard:

Virtuelle Methoden Kapitel 11 Rein virtuelle Methoden / abstrakte Klassen aus dem C++ Standard: “An abstract class is a class that can be used only as a base class of some other class; no objects of an abstract class can be created except as subobjects of a class derived from it. A class is abstract if it has at least one pure virtual function. “ 1. Eine Klasse heißt abstrakt, wenn sie mindestens eine rein virtuelle Funktion hat. 2. Abstrakte Klassen können nicht instantiiert werden. 3. Abstrakte Klassen können als Basisklassen für andere Klassen benutzt werden. G. Rudolph: Einführung in die Programmierung ▪ WS 2017/18 20

Virtuelle Methoden Kapitel 11 Rein virtuelle Methoden class Ausgabe. Geraet { protected: bool Kann.

Virtuelle Methoden Kapitel 11 Rein virtuelle Methoden class Ausgabe. Geraet { protected: bool Kann. Farben; Data data; public: virtual void Farbdruck() = 0; void Drucke(); abstrakte Klasse }; void Ausgabe. Geraet: : Drucke() { if (Kann. Farben) Farbdruck(); else cout << data; } Man kann rein virtuelle Methode verwenden, ohne dass Code vorhanden ist! Warum? G. Rudolph: Einführung in die Programmierung ▪ WS 2017/18 21

Virtuelle Destruktoren Kapitel 11 Wird ein Objekt einer abgeleiteten Klasse über einen Verweis /

Virtuelle Destruktoren Kapitel 11 Wird ein Objekt einer abgeleiteten Klasse über einen Verweis / Zeiger auf die Basisklasse frei gegeben, dann muss der Destruktor in der Basisklasse virtuell sein! Warum? Wenn nicht virtuell, dann Bindung des Destruktors statisch zur Übersetzungszeit! Immer Aufruf des Destruktors der Basisklasse! G. Rudolph: Einführung in die Programmierung ▪ WS 2017/18 22

Virtuelle Destruktoren Kapitel 11 class Familie { public: ~Familie() { cout << “D: Familie“

Virtuelle Destruktoren Kapitel 11 class Familie { public: ~Familie() { cout << “D: Familie“ << endl; } }; class Sohn : public Familie { ~Sohn() { cout << “D: Sohn“ << endl; } }; class Tochter : public Familie { ~Tochter() { cout << “D: Tochter“ << endl; } }; int main() { Familie *fam[3] = { new Familie, new Sohn, new Tochter }; delete fam[0]; delete fam[1]; delete fam[2]; return 0; } Ausgabe: D: Familie G. Rudolph: Einführung in die Programmierung ▪ WS 2017/18 23

Virtuelle Destruktoren Kapitel 11 class Familie { public: virtual ~Familie() { cout << “D:

Virtuelle Destruktoren Kapitel 11 class Familie { public: virtual ~Familie() { cout << “D: Familie“ << endl; } }; class Sohn : public Familie { ~Sohn() { cout << “D: Sohn“ << endl; } }; class Tochter : public Familie { ~Tochter() { cout << “D: Tochter“ << endl; } }; int main() { Familie *fam[3] = { new Familie, new Sohn, new Tochter }; delete fam[0]; delete fam[1]; delete fam[2]; return 0; D: Familie } D: Sohn Ausgabe: D: Familie D: Tochter D: Familie G. Rudolph: Einführung in die Programmierung ▪ WS 2017/18 24

Virtuelle Methoden – und die Realität? Kapitel 11 Renderer Klassenhierarchie virtual VBHandle alloc. VB(…)

Virtuelle Methoden – und die Realität? Kapitel 11 Renderer Klassenhierarchie virtual VBHandle alloc. VB(…) = 0; virtual void bind. Shader(…) = 0; virtual void draw. Static. Geom(…) = 0; virtual void init. Device. Context(…) = 0; Renderer. PS 3 Renderer. DX 9 Renderer. DX 10 alloc. VB(…){…} alloc. VB(…) … … bind. Shader(…) draw. Static. Geom(…) Renderer* renderer; init. Device. Context(…) if(game. Options->use. DX 9()){ renderer = new Renderer. DX 9(); } else if(game. Options->use. DX 10()){ Renderer. XB 360 init. Device. Context(…) renderer = new Renderer. DX 10(); } else if(. . . G. Rudolph: Einführung in die Programmierung ▪ WS 2017/18 25

Virtuelle Methoden – und die Realität? Kapitel 11 Renderer Klassenhierarchie virtual VBHandle alloc. VB(…)

Virtuelle Methoden – und die Realität? Kapitel 11 Renderer Klassenhierarchie virtual VBHandle alloc. VB(…) = 0; virtual void bind. Shader(…) = 0; virtual void draw. Static. Geom(…) = 0; virtual void init. Device. Context(…) = 0; Renderer. PS 3 Renderer. DX 9 Renderer. DX 10 alloc. VB(…){…} alloc. VB(…) … … bind. Shader(…) draw. Static. Geom(…) void Game. Engine: : init() { init. Device. Context(…) . . . renderer->init. Device. Context(); Renderer. XB 360 for(int i=0; i < static. Geom->size(); ++i){ init. Device. Context(…) Object 3 D* g = static. Geom->get(i); VBHandle h = renderer->alloc. VB(g->get. Triangle. Count()); G. Rudolph: Einführung in die Programmierung ▪ WS 2017/18 26

Vorläufiges Schlusswort Kapitel 11 Wofür machen wir das alles (Vererbung, virtuelle Funktionen, Zeiger, Rekursion)?

Vorläufiges Schlusswort Kapitel 11 Wofür machen wir das alles (Vererbung, virtuelle Funktionen, Zeiger, Rekursion)? Joel Spolsky – Back to basics: http: //www. joelonsoftware. com/articles/fog 0000000319. html verified: 03. 01. 2018 If you want to teach somebody something well, you have to start at the very lowest level. It's like Karate Kid. Wax On, Wax Off. Do that for three weeks. Then Knocking The Other Kid's Head off is easy. G. Rudolph: Einführung in die Programmierung ▪ WS 2017/18 27