32
OOP und Angewandte Mathematik Eine Einführung in die Anwendung objektorientierter Konzepte in der angewandten Mathematik WS 2011/12 WS 2011/12

OOP und Angewandte Mathematik - gm.fh-koeln.deafomusoe/WS2011_12/lecture07_2011_12.pdf · Templates Programmiersprachen sollten elegante Mechanismen besitzen, um Redundanz beim Programmieren

  • Upload
    doanh

  • View
    218

  • Download
    0

Embed Size (px)

Citation preview

OOP und Angewandte Mathematik

Eine Einführung in die Anwendungobjektorientierter Konzepte in derj p

angewandten Mathematik

WS 2011/12WS 2011/12

Inhalt

Templates Nochmal zusammengefasstg

Die Basis der OOP- Zusammengefasst

OOP und Angewandte Mathematik2

Fomuso Ekellem

Templates

Programmiersprachen sollten elegante Mechanismen besitzen, um Redundanz beim Programmieren vermeiden zu können.

Angenommen, wir wollen Listen-, Array, oder Matrizen-Klassen implementieren, die verschiedene Datentypen als Inhalt aufnehmen können(z.B. int, double, bool, usw…). Alle Operationen bleiben gleich:) p g

1 2 3 1.3 2.5 4.3 true false true4 5 6 3.4 5.2 6.3 true true true7 8 9 1 2 4 5 7 2 false true false7 8 9 1.2 4.5 7.2 false true false

In C++ wird dieses Konzept “Template” genannt. Eine andere Bezeichnung (z.B. in Java 1.5) ist “Generic”.

OOP und Angewandte Mathematik3

Fomuso Ekellem

Templates

Motivation: Eine Klasse erstellen für verschiedene Datentypen Datenrepräsentation: Matrix, Stacks, Listen, Bäume...p

Code für einen Datentyp sollte für kompatible Typen wieder verwendbar sein. C++ bietet die Möglichkeit, mit Hilfe von Templates (Schablonen, Vorlagen) eine

parametrisierte Familie verwandter Funktionen oder Klasse zu definierenparametrisierte Familie verwandter Funktionen oder Klasse zu definieren Funktions-Templates legen die Anweisung einer Funktion fest, wobei statt eines

konkreten Typs ein Parameter T gesetzt wird Klassen-Templates legen die Definition einer Klasse fest, wobei statt eines Typs ein Klassen Templates legen die Definition einer Klasse fest, wobei statt eines Typs ein

Parameter T eingesetzt wird.

Vorteile Ein Template muss nur einmal codiert werden Einzelne Klassen oder Funktionen Ein Template muss nur einmal codiert werden. Einzelne Klassen oder Funktionen

werden automatisch erzeugt. Einheitliche Lösung für gleichartige Probleme, wobei man unabhängige Bestandteile

frühzeitig testen kann

OOP und Angewandte Mathematik4

Fomuso Ekellem

Templates

Funktions-Templates Beispiel: swap()-Funktionp p() Verhalten ist für jeden Typ gleich (elementar und andere) Ineffizient: schreibe für jeden Typ eine eigene überladene Funktion

Lö d fi i i S h bl fü di F kti Lösung: definiere eine Schablone für die Funktionswap() für Typ <int> swap() für beliebigen Typ <T>

void swap (int& a, int& b) {template <class T>

void swap (int& a, int& b) {int tmp = a;a = b;b = tmp;}

void swap (T& a, T& b) {T tmp = a;a = b;b = tmp;}}

OOP und Angewandte Mathematik5

Fomuso Ekellem

Templates

Die template <...> Zeile sagtEin Template erwartet alsdem Compiler: „die folgende

Deklaration o. Definition ist alsSchablone zu verwenden“.

Ein Template erwartet alsArgumente Platzhalter fürTypen: Template-Parameter

template <class T>void swap (T& a, T& b) {T tmp = a;T tmp a;a = b;b = tmp;}

Die Platzhalter innerhalb des Template werden später (noch vor der Übersetzung in Maschinensprache) durch spezifische Typen ersetzt

OOP und Angewandte Mathematik6

Fomuso Ekellem

Templates

Templates sollen den Aufwand für den Entwickler reduzieren: Templates werden vom Kompiler nach Bedarf in eine normale Funktion/Klasse p p

gewandelt. Wird swap für 2 int-Werte verwendet, so wird eine weitere Funktion erzeugt. Wird swap für 2 Auto-Werte verwendet, so wird eine weitere Funktion erzeugt. Beim Kompilieren findet auch die Typprüfung statt.

Syntax für explizite Spezialisierung

double d1 = 4.0, d2 = 2.0;swap<double>(d1, d2);

Explizit bedeutet: der Programmierer spezifiziert ausdrücklich, mit welchem Typ die Templateparameter zu ersetzen sind.

OOP und Angewandte Mathematik7

Fomuso Ekellem

Templates

Implizite Spezialisierung

double d1 = 4.0, d2 = 2.0;//Alles klar: T = doubleswap(d1, d2);

double d1 = 4.0;float f1 = 10.0f;swap(d1, f1);

Das geht nicht ! Compiler meldet:no matching function for call to´swap(double&, float&)´

Entweder

swap<double>(d1, f1); Implizite Typkonvertierung von <f1>

Oder

swap(d1, double(f1)); Explizite Typkonvertierung von <f1>

OOP und Angewandte Mathematik8

Fomuso Ekellem

Templates

In vielen Anwendungen ist es nicht nur notwendig eine Funktion, sondern eine ganze Klasse mit einem Typ zu parametrisieren. Z.B.: Implementierung von elementaren Datenstrukturen wie Stack, Queue, binäre

Suchbäume,usw. Stack Beispiel

template <class T>class Stack {

private:T* inhalt // Datenbereich des StacksT* inhalt; // Datenbereich des Stacksint index, size; // Aktueller Index, Grösse des Stackspublic:Stack(int s): index(-1), size(s) { // Constructorinhalt = new T[size]; // Stack als Array implementiert}}void push(T item) { // Ein Element auf den Stack "pushen"if (index < (size - 1)) {inhalt[++index] = item;}}}T top() const { // Ein Element vom Stack lesenif (index >= 0) {return inhalt[index];}}void pop() { // Ein Element auf dem Stack löschenif (index >= 0) {--index;}

OOP und Angewandte Mathematik9

Fomuso Ekellem

if (index 0) { index;}}

};

Templates

Gebrauch der Template-Klasse Stack

int main() {Stack<int> intStack(100); // Stack für 100 intStack<double> doubleStack(250); // Stack für 250 doubleStack<rect> rectStack(50); // Stack für 50 rectintStack push(7);intStack.push(7);doubleStack.push(3.14);rectStack.push(rect(2,5));}

Bei der Allozierung eines Stacks muss explizit der Typ angegeben werden(<int>, <rect>, ...)

Auch hier gilt: die entsprechende Klasse wird vom Compiler bei Bedarf aus der Auc e g lt: d e e tsp ec e de lasse w d vo Co p le be Beda f aus de Template-Klasse generiert.

OOP und Angewandte Mathematik10

Fomuso Ekellem

Templates

Nochmals die Template-Klasse Stack, diesmal aber mit Trennung von Deklaration und Definition: Definition: stack.cppHeader-Datei: stack.h

template <class T>class Stack {

#include "stack.h"using namespace std;// Achtung: nicht Stack::Stack(int s)!template <class T>Stack<T>::Stack(int s):index( 1) size(s){

private:T* inhalt;int index;int size;

public:

Stack<T>::Stack(int s):index(-1),size(s){inhalt = new T[size];}template <class T>

public:Stack(int s);void push(Type item);T top() const;void pop();

}

void Stack<T>::push(T item) {if(index<size) {inhalt[++index]=item;}}template <class T>T Stack<T>::top() const {

};p() {

if (index>=0) {return inhalt[index];}}template <class T>void Stack<Type>::pop() {if (index >= 0) {index--;}

OOP und Angewandte Mathematik11

Fomuso Ekellem

if (index >= 0) {index--;}}

Templates

Gebrauch!!!

#i l d " k "#include "stack.cpp"using namespace std;int main() {Stack<int> intStack(100);Stack<double> doubleStack(250);intStack.push(7);doubleStack.push(3.14);}

Man beachte: stack.cpp, nicht stack.h!!! Bei Templates muss die komplette Implementierung eingebunden werden, weil

der Compiler die Klasse bei Bedarf erzeugt (Spezifikation allein reicht also nicht)de Co p le d e lasse be Beda f e eugt (Spe f at o alle e c t also c t) Dies gilt auch für Template Funktionen; Die Funktionsdeklaration allein reicht

nicht.

OOP und Angewandte Mathematik12

Fomuso Ekellem

Templates

Die Angabe des Datentyps beim Gebrauch eines Templates bestimmt, wofür eine Instanz des Templates gebraucht werden kann:

Ausnahme: auch Subklassen von Person können auf diesem Stack abgelegt werden.

Stack<Person> personStack(100); // Nur für Typ Person verwendbar

werden. Dabei werden die Objekte aber in Person konvertiert...

wodurch die in Subklassen spezifizierte Funktionalität (und damit auch Polymorphismus) verloren gehtPolymorphismus) verloren geht.

Besser: man verwendet einen Zeiger auf die Basisklasse:

l l h l d

Stack<Person*> personStack(100); // Für alle verwendbar

Vorteile: Polymorphismus funktioniert; Subklassen von Person können auf dem Stack abgelegt werden, ohne deren zusätzliche Information zu verlieren.

OOP und Angewandte Mathematik13

Fomuso Ekellem

Templates

Templates von Templates: Templates können als Parameter für andere Templates dienen:

complex<float> c1, c2;swap<complex<float> >(c1, c2);

complex<T> ist eine Klasse der C++ Standard Bibl. für Komplexe Zahlen (#include <complex>)A h B i h h l T l f i d f l d ‘ ‘ d h Achtung: Bei geschachtelten Templates muss man aufeinander folgende ‘>‘ durch Leerzeichen trennen, da sie sonst als shift-Operator missinterpretiert werden.

OOP und Angewandte Mathematik14

Fomuso Ekellem

Templates

Ein Template existiert nicht als Typ oder Objekt. Erst bei Instanziierung eines Template entsteht eine neuer Typ g p yp

(Funktion/Klasse) bei dem die Template-Parameter durch konkrete Typen ersetzt wurden.

Ohne Templates: Ohne Templates: werden Interface und Implementierung in separaten Dateien untergebracht (.h, .cpp) stellt der Linker die Verbindung zwischen dem Aufruf einer deklarierten Methode und

dem zusätzlichen Maschinen-Code her.

Mit Templates: wird Code erst bei Bedarf generiert. Bedarf heißt, z.B. durch Bindung an spezifische

Template-ParameterTemplate Parameter kann nur der vom Template generierte Code übersetzt und gelinkt werden.

OOP und Angewandte Mathematik15

Fomuso Ekellem

Klassen und Strukturen in C++

Die Basis der OOP- Zusammengefasst C++ erlaubt unter anderen die Deklaration von Klassen und Strukturen zur

Strukturierung eines OOP-Programms. Klassen und Strukturen unterscheiden sich in C++ prinzipiell kaum. In beiden

können Sie Eigenschaften und Methoden unterbringen.können Sie Eigenschaften und Methoden unterbringen. Klassen werden mit dem Schlüsselwort class deklariert, Strukturen mit struct. Alle Datenfelder in einer Struktur sind öffentlich. Klassen ermöglichen dagegen,

dass Datenfelder privat oder geschützt (protected) deklariert werden Strukturen dass Datenfelder privat oder geschützt (protected) deklariert werden. Strukturen ermöglichen somit nicht das wichtige Konzept der Kapselung.

class person{string Name; // private

struct person{string Name; // public

g pstring Nachname //private

public:void laufen(){ //public}

};

string Name; // publicstring Nachname //publicvoid laufen(){ //public}

};

OOP und Angewandte Mathematik16

Fomuso Ekellem

};

Klassen und Strukturen in C++

Strukturen können nur wie einfache Klassen behandelt werden, damit die Umsetzung von C-Quellcode nach C++ vereinfacht wird. Da die Strukturen die wichtige Kapselung nicht unterstützen, sollten Sie stattdessen immer Klassen einsetzen.

In dieser Vorlesung wird class immer benutzt!g

OOP und Angewandte Mathematik17

Fomuso Ekellem

Die Strukturierung einer Anwendung

Größere Programme erfordern eine Strukturierung des Quellcodes. Die Basis der Strukturierung ist in C++ eine Klasse.

Über Klassen erreichen Sie, dass Sie Programmcode wiederverwenden können und dass Sie Ihr Programm so strukturieren, dass die Fehlersuche und die Wartung erheblich erleichtert werden.g

Wenn Sie eine Klasse entwickeln, können Sie entscheiden, ob Sie eine echteKlasse (mit normalen Eigenschaften und Methoden) programmieren, aus der Sie später Instanzen erzeugen, oder ob Sie eine Klasse mit statischen Methoden und p g ,Eigenschaften erzeugen wollen.

Statische Methoden und Eigenschaften (Klassenmethoden, Klasseneigenschaften) können Sie auch ohne eine Instanz der Klasse aufrufen. ö e S e auc o e e e sta de lasse auf ufe .

Echte Klassen arbeiten echt objektorientiert, Klassen mit statischen Methoden und Eigenschaften simulieren (u. a.) die Module der strukturierten Programmierung.Programmierung.

OOP und Angewandte Mathematik18

Fomuso Ekellem

Einfache Klassen und deren Anwendung

Grundlagen zur Programmierung von Klassen In einer C++-Datei (mit der Endung .cpp oder .cc) können Sie eine oder mehrere ( g pp )

Klassen implementieren. Sie können Klassen komplett in der cpp-Datei unterbringen und auf eine

Headerdatei verzichten oderHeaderdatei verzichten oder In h-Datei und cpp-Datei trennen. Die h-Datei (Headerdatei) enthält die

Deklaration der Klasse, die cpp-Datei enthält die Implementierung der Methoden der Klasseder Klasse.

In einer cpp-Datei können Sie eine oder mehrere Klassen unterbringen. In der Praxis werden Klassen oft in separaten Dateien deklariert, um diese einfach

i d P i d d köin anderen Programmen wiederverwenden zu können. Diese Trennung macht auch dann Sinn, wenn Sie Ihre Klassen in Bibliotheken

(mit der Endung .lib) kompilieren und diese Bibliotheken für die eigene V d i i O d i hVerwendung in einem separaten Ordner speichern.

OOP und Angewandte Mathematik19

Fomuso Ekellem

Einfache Klassen und deren Anwendung

Objekte statisch erzeugen Statisch erzeugen Sie ein Objekt, indem Sie eine Objektvariable wie eine einfache g j , j

Variable deklarieren:

Statisch bedeutet hier dass C++ das Objekt auf dem Stack speichert Der Stack ist

Kreis k; // statische Erzeugung

Statisch bedeutet hier, dass C++ das Objekt auf dem Stack speichert. Der Stack ist ein Speicherbereich, den alle Programme besitzen und auf dem u. A. alle lokalen Variablen einer Funktion oder Methode gespeichert werden.

Da der Stack nach der Ausführung der Funktion/Methode wieder automatisch Da der Stack nach der Ausführung der Funktion/Methode wieder automatisch bereinigt wird, werden statische Objekte also automatisch zerstört, wenn die Funktion bzw. Methode beendet ist.

Ei P bl b i t ti h Obj kt i t d Obj kt kö t ß i d Ein Problem bei statischen Objekten ist, das Objekt könnte zu groß sein, und man muss bei der Entwicklung immer beachten wie viele Objekt erzeugt werden müssen.

OOP und Angewandte Mathematik20

Fomuso Ekellem

Einfache Klassen und deren Anwendung

Objekte dynamisch erzeugen Für die dynamische Erzeugung von Objekten deklarieren Sie die Objektvariable y g g j j

als Zeiger:

Dann erzeugen Sie das Objekt über den new Operator:

Kreis * k; // dynamische Erzeugung

Dann erzeugen Sie das Objekt über den new-Operator:

Dynamisch erzeugte Objekte werden auf dem Heap angelegt. Der Heap ist ein S i h b i h d f l b l D i i A f d H d

Kreis = new Kreis

Speicherbereich, der für globale Daten reserviert ist. Auf dem Heap werden außerdem alle Funktionen und Klassen einer Anwendung gespeichert. Die Größe des Heap ist nur durch den im System verfügbaren Speicher begrenzt.

So kann Ihre Anwendung während des Programmablaufs (eben dynamisch) nahezu beliebig viele Objekte erzeugen.

OOP und Angewandte Mathematik21

Fomuso Ekellem

Einfache Klassen und deren Anwendung

Objekte dynamisch erzeugen Objekte, die dynamisch erzeugt wurden, können über eine Dereferenzierung des j , y g , g

Zeigers angesprochen werden:

Durchgesetzt hat sich aber die Kurzschreibweise die mit dem Operator >

(*k). Radius = 20

Durchgesetzt hat sich aber die Kurzschreibweise, die mit dem Operator -> arbeitet:

D i h Obj k Si i ll d i h i

k->Radius = 20

Dynamisch erzeugt Objekte müssen Sie wie alle dynamisch reservierten Speicherbereiche über die delete-Anweisung aus dem Speicher entfernen.

delete k;

Vergessen Sie dies, bleibt das Objekt im Speicher, so lange Ihre Anwendung läuft, und verbraucht unnötig Ressourcen.

OOP und Angewandte Mathematik22

Fomuso Ekellem

Einfache Klassen und deren Anwendung

Die Bedeutung des Stack Der Stack ist ein spezieller Speicherbereich, den jedes Programm besitzt und der p p , j g

wie ein Stapel arbeitet: Daten werden der Reihe nach auf dem Stapel abgelegt und können auch wieder, der Reihe nach, vom Stapel entfernt werden. (Last in firstout-LIFO))

Der Stack wird vom Compiler automatisch über Funktionen angesprochen, die Daten auf dem Stapel ablegen, Daten vom Stapel auslesen und vom Stapel löschen. p

OOP und Angewandte Mathematik23

Fomuso Ekellem

Einfache Klassen und deren Anwendung

Die Bedeutung des Stack : Beispiel

Beim Aufruf der Funktion Add int Add(int x, int y){

int result;result = x + y;

Beim Aufruf der Funktion Add, legt der Compiler die folgenden Daten auf dem Stack an:1. einen Speicherbereich für

den Rückgabewert der return result;}

void main(void){

den Rückgabewert der Funktion,

2. die Adresse, zu der das Programm nach der Ausführung zurückspringen {

int i = Add(1, 2);cout << I;

}

Ausführung zurückspringen muss,

3. die Argumente der Funktion,4. und die lokalen Variablen der

F k iFunktion.

OOP und Angewandte Mathematik24

Fomuso Ekellem

Einfache Klassen und deren Anwendung

Wie werden Objekte gespeichert? Um zu verstehen wie z.B den Polymorphismus und virtuellen Methoden

funktionieren, müssen Sie wissen wie, Objekte prinzipiell gespeichert werden. Eine Instanz einer Klasse besteht prinzipiell nur aus den Datenfeldern der Klasse

(außer, wenn die Klasse Inline-Methoden beinhaltet, die innerhalb der Instanz (gespeichert werden).

Beispielclass Punkt

class Kreis{public:

int x;int y;void set(int x, int y)

class Kreis{public:

int Radius;int Farbe;d bl U f

( , y){

this->x = x;this->y = y;

}};

double Umfang{

return Radius * 2 * 3.1415927;}

};

OOP und Angewandte Mathematik25

Fomuso Ekellem

};

Einfache Klassen und deren Anwendung

Wie werden Objekte gespeichert?

void main(void){

Kreis k1;Kreis k2;P kt 1Punkt p1;

k1.Radius = 100;k1.Farbe = 255;k2.Radius = 200;k2.Farbe = 1024;

p1.Set(10, 11);}

k1, k2 und p1 sind also Variablen, die auf die Adresse zeigen, an der die Eigenschaften des Objekts gespeichert sind. Dieses Vorgehen reduziert den Speicherbedarf von Objekten enorm

OOP und Angewandte Mathematik26

Fomuso Ekellem

Speicherbedarf von Objekten enorm.

Einfache Klassen und deren Anwendung

Der this-Zeiger Damit eine Methode, die ja normalerweise (wenn es keine Inline-Methode ist), die

Eigenschaften der aufrufenden Instanz bearbeiten kann, übergibt der Compiler der Methode ein zusätzliches, unsichtbares Argument, den this->Zeiger.

double Umfang(Kreis *this){

return this->Radius * 2 * 3.1415927;}

Dieser Zeiger zeigt auf die Objektinstanz, von der aus der Aufruf erfolgt ist. Wenn Sie in einer Methode auf Eigenschaften oder Datenfelder des Objekts zugreifen oder

andere Methoden aufrufen, stellt der Compiler diesen Zeiger implizit vor den Namen des verwendeten Klassenelements, falls dies noch nicht explizit geschehen ist und falls ein entsprechendes Klassenelement gefunden wird. Siehe nächste Folie...

OOP und Angewandte Mathematik27

Fomuso Ekellem

Einfache Klassen und deren Anwendung

Konkretes this-> Beispiel

class Kreis{public:

main:

Kreis k1 // Statisch deklariertK1 als Objekt hat Radius und Farbe als Eigenschaften und kann Umfang (Methode)aufrufen Implizit sieht im kompilierten public:

int Radius;int Farbe;double Umfang{

t R di * 2 * 3 1415927

g ( ) p pProgrammcode demnach so aus, falls noch nicht so definiert ist

double Umfang(Kreis *this){

return this->Radius * 2 * 3 1415927;return Radius * 2 * 3.1415927;}

};

return this->Radius 2 3.1415927;}

K1 (ist Aufrufer)

this ist der der zu eine gegebene Zeit eine Funktion Ausführt

OOP und Angewandte Mathematik28

Fomuso Ekellem

OOP

Nächste Woche...

OOP und Angewandte Mathematik29

Fomuso Ekellem

Die Basis der OOP- Zusammengefasst

Die Sichtbarkeit von Klassenelementen Daten schützen: Die Kapselung p g

Die klassische Kapselung Bessere Kapselung mit Ausnahmen

Konstruktoren und Destruktoren Konstruktoren und Destruktoren Konstruktoren Der Copy-Konstruktor Der Destruktor Der Destruktor

Assoziationen zwischen Objekten

OOP und Angewandte Mathematik30

Fomuso Ekellem

Die Basis der OOP- Zusammengefasst

Vererbung Warum Vererbung? g Das Beispiel Die Grundlagen der Vererbung

Di N d fi iti M th d Die Neudefinition von Methoden Verwenden geerbter Elemente Die Sichtbarkeit bei der Vererbung Veröffentlichen von privaten und geschützten Elementen in abgeleiteten Klassen Vererbung von Konstruktoren und Destruktoren Polymorphismus und virtuelle Methoden Polymorphismus und virtuelle Methoden public-, protected- und private-Ableitung Mehrfachvererbung

OOP und Angewandte Mathematik31

Fomuso Ekellem

OOP-Specials

Abstrakte Klassen und Methoden Statische Klassenelemente

Statische Eigenschaften (Klasseneigenschaften) Statische Methoden (Klassenmethoden)

Verschachtelte Klassen Verschachtelte Klassen Friends Operatoren für Klassen Schnittstellen

OOP und Angewandte Mathematik32

Fomuso Ekellem