Polymorphie (Vielgestaltigkeit). Wenn eine Methode, wie z.B. print für verschiedene Programmteile...

42
Polymorphie (Vielgestaltigke it)

Transcript of Polymorphie (Vielgestaltigkeit). Wenn eine Methode, wie z.B. print für verschiedene Programmteile...

Page 1: Polymorphie (Vielgestaltigkeit). Wenn eine Methode, wie z.B. print für verschiedene Programmteile steht (und z.B. einmal Objekte verschiedener Klassen.

Polymorphie(Vielgestaltigkeit)

Page 2: Polymorphie (Vielgestaltigkeit). Wenn eine Methode, wie z.B. print für verschiedene Programmteile steht (und z.B. einmal Objekte verschiedener Klassen.

Wenn eine Methode, wie z.B. print für verschiedene Programmteile steht (und z.B. einmal Objekte verschiedener Klassen wie z.B. Rechtecke oder das andere Mal Kreise auf dem Bildschirm ausgeben bzw. zeichnen kann), dann nennt man dies Polymorphie

Page 3: Polymorphie (Vielgestaltigkeit). Wenn eine Methode, wie z.B. print für verschiedene Programmteile steht (und z.B. einmal Objekte verschiedener Klassen.

Beispiel:In einem Feld sollen verschiedene Objekte (entweder Rechtecke oder Kreise) abgespeichert und dann (z.B. zu Testzwecken) deren spezifischen Daten (Länge und Breite bzw. Radius) ausgegeben werden

Page 4: Polymorphie (Vielgestaltigkeit). Wenn eine Methode, wie z.B. print für verschiedene Programmteile steht (und z.B. einmal Objekte verschiedener Klassen.

Die Reihenfolge der Objekte (Rechteck bzw. Kreis) in dem Feld soll vom Anwender bestimmt werden bzw. zufällig sein.

Page 5: Polymorphie (Vielgestaltigkeit). Wenn eine Methode, wie z.B. print für verschiedene Programmteile steht (und z.B. einmal Objekte verschiedener Klassen.

Aber Halt:In einem Feld können nur Objekte der gleichen Klasse gespeichert werden.

Page 6: Polymorphie (Vielgestaltigkeit). Wenn eine Methode, wie z.B. print für verschiedene Programmteile steht (und z.B. einmal Objekte verschiedener Klassen.

Deswegen muß man eine Oberklasse von Rechteck und Kreis erzeugen und Objekte (genauer Pointer; siehe später) der Oberklasse Objekte der Unterklassen Rechteck oder Kreis zuweisen und die Objekte der Oberklasse im Feld speichern.

Page 7: Polymorphie (Vielgestaltigkeit). Wenn eine Methode, wie z.B. print für verschiedene Programmteile steht (und z.B. einmal Objekte verschiedener Klassen.

Vorgehensweise:Man erzeugt die Klassen Rechteck und Kreis mit jeweils der spezifischen print Funktion, die den Flächeninhalt und den Umfang des Rechtecks bzw. des Kreises ausgibt.

Page 8: Polymorphie (Vielgestaltigkeit). Wenn eine Methode, wie z.B. print für verschiedene Programmteile steht (und z.B. einmal Objekte verschiedener Klassen.

Dann erzeugt man eine gemeinsame Basisklasse, z.B. mit dem Namen Form der Klassen Rechteck und Kreis.

Page 9: Polymorphie (Vielgestaltigkeit). Wenn eine Methode, wie z.B. print für verschiedene Programmteile steht (und z.B. einmal Objekte verschiedener Klassen.

In UML-Darstellung:

Page 10: Polymorphie (Vielgestaltigkeit). Wenn eine Methode, wie z.B. print für verschiedene Programmteile steht (und z.B. einmal Objekte verschiedener Klassen.

Form

Rechteck Kreis

Page 11: Polymorphie (Vielgestaltigkeit). Wenn eine Methode, wie z.B. print für verschiedene Programmteile steht (und z.B. einmal Objekte verschiedener Klassen.

Mit new werden (in einer Schleife) jeweils Pointer auf ein Rechteck bzw. einen Kreis erzeugt und einem Pointer auf Form zugewiesen und dieser Pointer in einem Element des Feldes abgespeichert.

Page 12: Polymorphie (Vielgestaltigkeit). Wenn eine Methode, wie z.B. print für verschiedene Programmteile steht (und z.B. einmal Objekte verschiedener Klassen.

Als Programm-Skizze

Page 13: Polymorphie (Vielgestaltigkeit). Wenn eine Methode, wie z.B. print für verschiedene Programmteile steht (und z.B. einmal Objekte verschiedener Klassen.

Bemerkung:Der Einfachheit halber ist die Reihenfolge der Rechtecke bzw. Kreise in der folgenden Programm-Skizze nicht zufällig bzw. vom Anwender vorgegeben und außerdem ist die Schleife weggelassen worden.

Page 14: Polymorphie (Vielgestaltigkeit). Wenn eine Methode, wie z.B. print für verschiedene Programmteile steht (und z.B. einmal Objekte verschiedener Klassen.

Form *f[10];Kreis *kp;Rechteck *rp;

kp = new Kreis();rp = new Rechteck();

f[0] = rp;f[1] = kp;

f[0]->print();f[1]->print();

Einem Pointer auf Form wird ein Pointer auf Rechteck zugewiesen

Einem Pointer auf Form wird ein Pointer auf Kreis zugewiesen

Die print() Methode wird aufgerufen, die in der Klasse Rechteck implementiert wurde.

Die print() Methode wird aufgerufen, die in der Klasse Kreis implementiert wurde.

Dazu muß print als virtuelle Funktion deklariert werden, d.h. der Name print wird an die Funktion nicht während der Kompilierung gebunden, sondern während der Laufzeit

Page 15: Polymorphie (Vielgestaltigkeit). Wenn eine Methode, wie z.B. print für verschiedene Programmteile steht (und z.B. einmal Objekte verschiedener Klassen.

Das exakte Programm:

Page 16: Polymorphie (Vielgestaltigkeit). Wenn eine Methode, wie z.B. print für verschiedene Programmteile steht (und z.B. einmal Objekte verschiedener Klassen.

#include "stdafx.h"#include <iostream>#include <time.h>

using namespace std;

Page 17: Polymorphie (Vielgestaltigkeit). Wenn eine Methode, wie z.B. print für verschiedene Programmteile steht (und z.B. einmal Objekte verschiedener Klassen.

class Form{ public: virtual void print();}; // Form

class Rechteck: public Form{ private: double l; double b;

public: Rechteck(double ll, double bb); ~Rechteck(); virtual void print();}; // Rechteck

Durch den Bezeichner virtual wird print eine virtuelle Funktion. Die Verwendung von virtual ist nur innerhalb einer Klassendeklaration zulässig.

Der Bezeichner virtual vererbt sich und muß daher nicht mehr (kann aber) in den Subklassen wiederholt zu werden.

Page 18: Polymorphie (Vielgestaltigkeit). Wenn eine Methode, wie z.B. print für verschiedene Programmteile steht (und z.B. einmal Objekte verschiedener Klassen.

class Kreis: public Form{ private: double r;

public: Kreis(double rr); ~Kreis(); virtual void print();}; // Kreis

Der Bezeichner virtual vererbt sich und muß daher nicht mehr (kann aber) in den Subklassen wiederholt zu werden.

Page 19: Polymorphie (Vielgestaltigkeit). Wenn eine Methode, wie z.B. print für verschiedene Programmteile steht (und z.B. einmal Objekte verschiedener Klassen.

void Form::print(){};

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

Rechteck::~Rechteck(){};

void Rechteck::print(){ cout << "Rechteck: Laenge =" << l << " Breite =" << b;};

print wird in der Klasse Rechteck redefiniert (neu implementiert).

Page 20: Polymorphie (Vielgestaltigkeit). Wenn eine Methode, wie z.B. print für verschiedene Programmteile steht (und z.B. einmal Objekte verschiedener Klassen.

Kreis::Kreis(double rr){ r = rr;}

Kreis::~Kreis(){}

void Kreis::print(){ cout << "Kreis: Radius = " << r << endl;}

print wird in der Klasse Kreis redefiniert (neu implementiert).

Page 21: Polymorphie (Vielgestaltigkeit). Wenn eine Methode, wie z.B. print für verschiedene Programmteile steht (und z.B. einmal Objekte verschiedener Klassen.

int main(){ int r,i; Form *v[10];

srand((unsigned)time(NULL));

for(i=0;i<10;i++){ r = rand()%2; if(r==0) v[i] = new Kreis(100*i); else v[i] = new Rechteck(10*i, 20*i); }

Es wird ein Feld v mit 10 Pointern auf Objekte der Klasse Form reserviert.

r ist eine Zufallszahl, die entweder den Wert 0 oder 1 annimmt.

legt ein Objekt der Klasse Kreis an, liefert einen Pointer darauf zurück und weist ihn einem Feldelement (pointer auf Form) zu.

Dies funktioniert, weil: "Oberklasse = Unterklasse" korrekt ist.

legt ein Objekt der Klasse Kreis an, liefert einen Pointer darauf zurück .

Page 22: Polymorphie (Vielgestaltigkeit). Wenn eine Methode, wie z.B. print für verschiedene Programmteile steht (und z.B. einmal Objekte verschiedener Klassen.

for(i=0;i<10;i++){ v[i]->print();

}

for(i=0;i<10;i++){ delete v[i];

} return(0);}

delete gibt den dynamisch erzeugten Speicher wieder frei.

Gibt jeweils den Radius des Kreises eines Feldelements bzw. Breite und Länge des Rechtecks aus.

Page 23: Polymorphie (Vielgestaltigkeit). Wenn eine Methode, wie z.B. print für verschiedene Programmteile steht (und z.B. einmal Objekte verschiedener Klassen.

Frage:Wäre das folgende abgeänderte Programm auch korrekt ?

Bem:Im Vergleich zum letzten Programm wurde nur der rot gekennzeichnete Quellcode in main() geändert.Alles andere ist gleich.

Page 24: Polymorphie (Vielgestaltigkeit). Wenn eine Methode, wie z.B. print für verschiedene Programmteile steht (und z.B. einmal Objekte verschiedener Klassen.

void main(){ int r; int i; Form vv[10];

srand((unsigned)time(NULL));

Es wird ein Feld vv mit 10 Objekten der Klasse Form reserviert.

Page 25: Polymorphie (Vielgestaltigkeit). Wenn eine Methode, wie z.B. print für verschiedene Programmteile steht (und z.B. einmal Objekte verschiedener Klassen.

for(i=0;i<10;i++){ Rechteck re(10*i, 20*i); Kreis kr(100*i); r = rand()%2; if(r==0) vv[i] = kr; else vv[i] = re;

}

for(i=0;i<10;i++) vv[i].print();}

legt bei jedem Durchgang ein Objekt der Klasse Kreis an.

Späte Bindung funktioniert nur, wenn der Zugriff über einen Pointer auf ein Objekt der Basisklasse erfolgt. Da dies hier nicht der Fall ist, wird die frühe Bindung verwendet. Der Typ der Variablen vv (also Form) bestimmt, welche print()-Funktion aufgerufen wird. Diese print()-Funktion der Klasse Form gibt aber nichts auf dem Bildschirm aus.

legt bei jedem Durchgang ein Objekt der Klasse Rechteck an.

Page 26: Polymorphie (Vielgestaltigkeit). Wenn eine Methode, wie z.B. print für verschiedene Programmteile steht (und z.B. einmal Objekte verschiedener Klassen.

Rein virtuelle Funktionen auch pure function (englisch) oderabstrakte Funktionen genannt

Page 27: Polymorphie (Vielgestaltigkeit). Wenn eine Methode, wie z.B. print für verschiedene Programmteile steht (und z.B. einmal Objekte verschiedener Klassen.

Motivation

Page 28: Polymorphie (Vielgestaltigkeit). Wenn eine Methode, wie z.B. print für verschiedene Programmteile steht (und z.B. einmal Objekte verschiedener Klassen.

Hat es Sinn, im letzten Programm eine Instanz der Klasse Form zu bilden ?

Nein, die Klasse Form ist nur dazu da, eine Basisklasse der Klassen Rechteck und Kreis zu bilden. Die Klasse Form besitzt nicht einmal ein Attribut, sondern nur die Methode print(), die nichts macht.

Page 29: Polymorphie (Vielgestaltigkeit). Wenn eine Methode, wie z.B. print für verschiedene Programmteile steht (und z.B. einmal Objekte verschiedener Klassen.

Was passiert, wenn der Programmierer aus Versehen vergessen hat, in einer der Subklassen, z.B. Rechteck, die print() Methode zu deklarieren und zu definieren (implementieren) ?

Dann wird die virtuelle Funktion print() der Basisklasse in die Subklasse Rechteck vererbt. Ein Aufruf der Funktion print() der Klasse Rechteck macht dann also das gleiche wie ein Aufruf der Funktion print() der Klasse Form (nämlich gar nichts, weil sie keine Anweisungen besitzt).

Page 30: Polymorphie (Vielgestaltigkeit). Wenn eine Methode, wie z.B. print für verschiedene Programmteile steht (und z.B. einmal Objekte verschiedener Klassen.

Um zu verhindern, daß 1) Instanzen einer Klasse gebildet werden und um zu verhindern, daß 2) ein Programmierer vergisst, eine virtuelle Funktion in einer Subklasse zu deklarieren und zu definieren (implementieren), wurden die sogenannten rein virtuellen Funktionen eingeführt.

Page 31: Polymorphie (Vielgestaltigkeit). Wenn eine Methode, wie z.B. print für verschiedene Programmteile steht (und z.B. einmal Objekte verschiedener Klassen.

Eine rein virtuelle Funktion (abstrakte Funktion) ist eine virtuelle Funktion mit dem Zusatz =0

Beispiel:virtual print()=0;

Das =0 bedeutet: Diese Funktion muss nicht (kann aber) in der Klasse implementiert werden.

Page 32: Polymorphie (Vielgestaltigkeit). Wenn eine Methode, wie z.B. print für verschiedene Programmteile steht (und z.B. einmal Objekte verschiedener Klassen.

Besitzt eine Klasse mindestens eine abstrakte Funktion (rein virtuelle Funktion), dann heißt diese Klasse abstrakte Klasse. Von dieser darf dann keine Instanz gebildet werden (wohl aber Pointer auf Objekte dieser abstrakten Klasse).

Page 33: Polymorphie (Vielgestaltigkeit). Wenn eine Methode, wie z.B. print für verschiedene Programmteile steht (und z.B. einmal Objekte verschiedener Klassen.

Was muss man im letzten Programm abändern, damit sichergestellt wird, daß von der Klasse Form keine Instanz gebildet werden kann ?

Die Programmierzeile:virtual void print();in der Klasse Form muß ersetzt werden durch:virtual void print()=0;

Page 34: Polymorphie (Vielgestaltigkeit). Wenn eine Methode, wie z.B. print für verschiedene Programmteile steht (und z.B. einmal Objekte verschiedener Klassen.

Was passiert, wenn der Programmierer im letzten Programm aus Versehen vergessen hat, in einer der Subklassen, z.B. Rechteck, die print() Methode zu deklarieren und zu definieren (implementieren) ?

Page 35: Polymorphie (Vielgestaltigkeit). Wenn eine Methode, wie z.B. print für verschiedene Programmteile steht (und z.B. einmal Objekte verschiedener Klassen.

Hier nochmals das Programm:

Page 36: Polymorphie (Vielgestaltigkeit). Wenn eine Methode, wie z.B. print für verschiedene Programmteile steht (und z.B. einmal Objekte verschiedener Klassen.

#include "stdafx.h"#include <stdlib.h>#include <stdio.h>#include <time.h>

Page 37: Polymorphie (Vielgestaltigkeit). Wenn eine Methode, wie z.B. print für verschiedene Programmteile steht (und z.B. einmal Objekte verschiedener Klassen.

class Form{ public: virtual void print()=0;}; // Form

class Rechteck: public Form{ private: double l; double b;

public: Rechteck(double ll, double bb); ~Rechteck(); // virtual void print();}; // Rechteck

Durch die Bezeichnung = 0 wird eine rein virtuelle Funktion deklariert.

Es wurde "vergessen", print() zu deklarieren

Page 38: Polymorphie (Vielgestaltigkeit). Wenn eine Methode, wie z.B. print für verschiedene Programmteile steht (und z.B. einmal Objekte verschiedener Klassen.

class Kreis: public Form{ private: double r;

public: Kreis(double rr); ~Kreis(); virtual void print();}; // Kreis

Alles wie im letzten Programm (nichts wurde verändert).

Page 39: Polymorphie (Vielgestaltigkeit). Wenn eine Methode, wie z.B. print für verschiedene Programmteile steht (und z.B. einmal Objekte verschiedener Klassen.

// void Form::print(){// };

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

Rechteck::~Rechteck(){};/*void Rechteck::print(){ cout << "Rechteck: Laenge =" << l << " Breite =" << b;}; */

Es wurde "vergessen", print() zu definieren (implementieren)print() braucht in Form nicht mehr

implementiert zu werden.

Page 40: Polymorphie (Vielgestaltigkeit). Wenn eine Methode, wie z.B. print für verschiedene Programmteile steht (und z.B. einmal Objekte verschiedener Klassen.

Kreis::Kreis(double rr){ r = rr;}

Kreis::~Kreis(){}

void Kreis::print(){ cout << "Kreis: Radius = " << r << endl;}

Alles wie im letzten Programm (nichts wurde verändert).

Page 41: Polymorphie (Vielgestaltigkeit). Wenn eine Methode, wie z.B. print für verschiedene Programmteile steht (und z.B. einmal Objekte verschiedener Klassen.

void main(){ int r,i; Form *v[10];

srand((unsigned)time(NULL));

for(i=0;i<10;i++){ r = rand()%2; if(r==0) v[i] = new Kreis(100*i); else v[i] = new Rechteck(10*i, 20*i); }

Aber was meint der Compiler dazu, daß ein Objekt der Klasse Rechteck angelegt wird ?

Alles wie im letzten Programm (nichts wurde verändert).

Da die print() Funktion in der Klasse Rechteck fehlt (und damit nicht redefiniert wird), erbt Rechteck von Form die rein virtuelle Funktion print(). Da dann Rechteck eine rein virtuelle Funktion besitzt, kann auch keine Instanz von Rechteck erzeugt werden --> Compiler meldet Fehler. Damit kann der vergessliche Programmierer gezwungen werden, die Funktion print() in den Subklassen zu implementieren.

Page 42: Polymorphie (Vielgestaltigkeit). Wenn eine Methode, wie z.B. print für verschiedene Programmteile steht (und z.B. einmal Objekte verschiedener Klassen.

for(i=0;i<10;i++){ v[i]->print();

}

for(i=0;i<10;i++){ delete v[i];

}}

Alles wie im letzten Programm (nichts wurde verändert).