3. Exkurs in weitere Arten der Programmierung Inhalt: Objektorientierte Programmierung in C++ Logische Programmierung in Prolog Peter Sobe Objektorientierte Programmierung in C++ C++ ist eine objektorientierte Erweiterung der Sprache C Neu gegenüber C: Klassen und Objekte Klassen: Geben die Anordnung der Daten vor (vgl. struct) Enthalten Funktionen zur Initialisierung und zum Umgang mit den Daten Ergeben jeweils einen neuen Typ Objekte: Sind Variablen eines Klassentyps Peter Sobe 2 Aufbau einer Klassendeklaration in C++ Aufbau einer Klasse in C++ : class name { private: Deklaration der Datenelemente public: }; R.Grossmann / P. Sobe Definition der Methoden 3 Deklaration der Datenelemente Beispiel Klasse vektor Der Teil Deklaration der Datenelemente wird gemäß der Kapselung mit dem Zugriffsspezifizierer private eingeleitet. Dies wird bei Weglassen auch automatisch angenommen. Beispiel: class vektor { private: float x, float y, float z; //Dekl. Datenelemente public: ....... } Ein Vektor des R³ hat drei Komponenten als Datenelemente. Der Typ der Elemente ist hier float. R.Grossmann / P. Sobe 4 Deklaration der Datenelemente Allgemein dürfen zur Deklaration von Datenelementen alle in C/C++ bekannten Standardtypen (auch Zeiger, Felder, Strukturen usw. benutzt werden. Sind neue Typen über Klassen definiert, dürfen diese Typen dann auch zur Deklaration von Datenelementen anderer Klassen verwendet werden. Die Datenelemente einer Klasse bezeichnet man auch als Elementobjekte (auch engl. Member). Da eine Klasse einen eigenen Gültigkeitsbereich für Namen bildet, sind Datenelemente lokal bezüglich der Klasse und nur Methoden der Klasse können Zugriffe auf diese auslösen. R.Grossmann / P. Sobe 5 Klassendeklaration Innerhalb einer Klasse darf niemals eine weitere Klassendeklaration vorgenommen werden. Richtig: Falsch: class ABC { class ABC { }; class XYZ { class XYZ { }; }; }; int main() { … } int main() { … } P. Sobe 6 Deklaration / Definition / Aufruf von Methoden Methoden sind einer Klasse zugeordnet und bilden die Menge der Operationen, die mit den Objekten der Klasse ausführbar sind. Damit der Nutzer Methoden zur Manipulation der Objekte in seinem Anwendungsprogramm aufrufen kann, müssen diese in aller Regel in einem public-Teil verfügbar sein. Methoden sind – syntaktisch gesehen - Funktionen im Sinne von C/C++. Die Deklaration und Definition der Methoden genügt den Regeln für normale Funktionen. Durch die Bindung an die Klasse unterscheidet sich der Aufruf von Methoden gegenüber normalen Funktionen: normale Funktion f(x) Methode f(x) der Klasse T f(y); T a; a.f(y); R.Grossmann / P. Sobe 7 Definition von Methoden am Beispiel der Klasse vektor Definition von Inline-Methoden: class vektor { private: float x, float y, float z; //Dekl. Datenelemente public: void init(float i,float j,float k) { x=i; y=j; z=k;} float betrag(){return sqrt(x*x+y*y+z*z);} ______________________________________________ Gewöhnliche Trennung von Deklaration und Implementierung: class vektor { private: float x, float y, float z; //Dekl. Datenelemente public: void init(float i,float j,float k) ; float betrag(); ..... }; void vektor::init (float i,float j,float k) { x=i; y=j; z=k;} float vektor::betrag(){return sqrt(x*x+y*y+z*z);} R.Grossmann / P. Sobe 8 Inline-Definition von Elementfunktionen Beispiel Klasse vektor Code-Beispiele: oo_vektor1.cpp – Deklaration und Definition der Elementfunktionen zusammen. oo_vektor2.cpp – getrennte Deklaration und Definition. In größeren Softwareprojekten werden die Klassendeklarationen in Header-Dateien (*.h) vorgenommen. Die Methoden der Klasse werden getrennt in *.cpp-Dateien implementiert. R.Grossmann / P. Sobe 9 Konstruktor und Destruktor - obligatorische Methoden einer Klasse Damit eine ordnungsgemäße Arbeit mit Objekten einer Klasse möglich wird, z.B. Erzeugung, Zerstörung von Objekten, müssen einige spezielle Methoden immer definiert sein. Wenn Sie vom Programmierer nicht angegeben werden, so werden sie standardmäßig vom C++-Übersetzer erzeugt: mindestens ein Konstruktor zur Erzeugung (Instanziierung) eines Objektes. In C++ muss ein Konstruktor den Klassennamen als Funktionsnamen tragen, ohne die Angabe eines Funktionstyps (auch nicht void) vektor(float i,float j,float k) {....} Beispiel: Der leere Konstruktor wird (falls nicht angegeben) vom Übersetzer automatisch erzeugt (engl. Default Constructor) Beispiel: vektor(){} R.Grossmann / P. Sobe 10 Destruktor genau ein Destruktor zur Zerstörung (Freigabe) eines Objektes. In C++ muss der Destruktor den Klassennamen als Funktionsnamen mit einer vorangestellten Tilde tragen; er muss parameterlos sein. Beispiel: ~ vektor() {....} Wird der Destruktor vom Programmierer nicht angegeben, so wird ein leerer Standard-Destruktor angenommen. R.Grossmann / P. Sobe 11 Der Standard-Konstruktor einer Klasse Als Standard-Konstruktor einer Klasse wird ein Konstruktor bezeichnet, der parameterlos ist. Es kann deshalb nur einen Standard-Konstruktor geben. Wird vom Programmierer kein Konstruktor in der Klasse angegeben, dann erzeugt der Compiler diesen Default-StandardKonstruktor. Ein Standard-Konstruktor wird immer gebraucht, wenn ein Feld von Elementen der Klasse deklariert werden soll, z.B. vektor matrix[10]; matrix ist ein Feld mit 10 Vektoren. R.Grossmann / P. Sobe 12 Weitere Methoden der Klasse vektor vektor add(vektor a) { return vektor(x+a.x,y+a.y,z+a.z); } vektor sub(vektor a) { return vektor(x-a.x,y-a.y,z-a.z); } float mult(vektor a) { return x*a.x+y*a.y+z*a.z; } vektor kreuz(vektor a) { return vektor(y*a.z-z*a.y, z*a.x-x*a.z, x*a.y-y*a.x); } Jetzt kann man dieser Operationen in der Anwendung auf vektorObjekte anwenden: neu=a.add(c); //Addition neu=n.sub(a); //Subtraktion cout<<"\nSkalarprodukt="<< b.mult(c); //Skalarprodukt neu=b.kreuz(c); neu.drucke(); R.Grossmann / P. Sobe //Kreuzprodukt 13 Weitere Methoden der Klasse vektor Besonders wichtig ist, dass die Implementierungen der Funktionen einen vektor-Wert als Rückgabewert zurückgeben, z.B.: vektor add(vektor a) {return vektor(x+a.x,y+a.y,z+a.z);} Dadurch kann man fortlaufende Operationen kodieren, wie z.B. neu=n.add(a).add(b).sub(d); Hätte man add als void-Funktion implementiert, wäre das in dieser Weise nicht möglich gewesen. R.Grossmann / P. Sobe 14 Reihung (Felder) von Objekten Besitzt eine Klassendefinition einen Standard-Konstruktor (Konstruktor ohne Parameter), so können im Programm auch Felder mit Elementen dieses Typs deklariert werden. Beispiel: class vektor { private: float x,y,z ; public: vektor(){ } // Standardkonstruktor vektor(float ax,float ay,float az) {x=ax;y=ay;z=az; } ..... }; Im C++-Programm können jetzt Felder von Vektoren vereinbart werden: vektor vfeld[20]; vektor fv[4] = { v1, v2, v3, v4}; // v1-v4 sind Vektor-Objekte R.Grossmann, P. Sobe 15 Prinzip der Stapel-Datenstruktur Eine wichtige Datenstruktur ist der s.g. Stapel (engl. Stack). Er arbeitet nach dem LIFOPrinzip, Last in – First out. Die Implementation stellt den Stack als ein auf dem Speicher gereihtes Feld von Elementen dar, welche zunächst als vom Typ int angenommen werden. Index Element Position des nächsten zu speichernden Elementes ... n n-1 302 ... ... 1 7 0 49 R.Grossmann, P. Sobe top Nur das top-Element kann entfernt werden (pop) bottom 16 Beispiel Klasse stack / Klassendefinition class stack { private: int *st; int p; public: stack(int m=100) {st = new int[m]; p=0;} ~stack() { delete [] st;} void push(int v) {st[p++]= v; } int pop() {return st[--p];} int empty() {return !p;} }; Der Elementtyp für die stack-Elemente ist int . R.Grossmann, P. Sobe 17 typedef – Anweisung am Beispiel der Klasse stack Die Struktur und Arbeit mit dem stack hängt nicht vom Elementtyp für die stack-Elemente ab, d.h. das gleiche Prinzip würde auch für Elemente vom Typ char oder complex gelten. Deshalb wird ein eigener Typ eingeführt (per typedef-Anweisung), den man flexibel mit verschiedenen Basisdatentypen oder eigenen Strukturen verbinden kann. typedef char item ; // konkreter Typ wird festgelegt class stack { private: item *st; int p; public: stack(int m=100) {st = new item[m]; p=0;} ~stack() { delete [] st;} void push(item v) {st[p++]= v; } item pop() {return st[--p];} int empty() {return !p;} }; R.Grossmann, P. Sobe 18