Programmierkurs C++ Kapitel 7:Objektorientierte Programmierung Seite 1 Objektorientierte Programmierung If programming in PASCAL is like put in a straightjacket, then programming in C is like playing with knifes, and programming in C++ is like juggling chainsaws. Anonymous Grundkonzepte der objektorientierten Programmierung Kapselung mit dem Verbergen von Information Vererbung Polymorphismus dynamisches Binden Klassen Abstrakte Stufe: Eine Klasse ist die Schnittstelle (Interface), die das Verhalten eines Objektes definiert. Funktionale Schnittstelle für die Kommunikation mit dem Objekt. Black Box: Klassenobjekt Anwendungsprogramm Methodenaufrufe Implementierungsstufe: Eine Klasse ist eine syntaktische Einheit, die eine Menge von Daten und darauf bezogene Operationen beschreibt. Diese Daten und Operationen sind allen Objekten der Klasse gemeinsam. Klasse vs. Objekt Implementierungsstufe: Eine Klassendefinition entspricht einer struct- bzw. typedef-struct-deklaration. Ein Objekt ist die speicherwirksame Definition einer Größe von dem Klassentyp. Dabei erhält das Objekt einen Bezugsnamen.
Programmierkurs C++ Kapitel 7:Objektorientierte Programmierung Seite 2 Beispiel: einfache Kontenverwaltung einer Bank //Konto1.cpp: Das Programm realisert eine einfache Kontoverwaltung. //Es benutzt absichtlich nicht die Möglichkeiten der Datenkapselung //("Information hiding"), die innerhalb des Klassenkozeptes zur //Verfügung ständen. //Diese Version findet man im Programm Konto2.cpp. K t o 1 Stand 200.03 Variable vom Typ Konto Zinssatz 2.55 void Initialisieren(Konto &Kto, float Stand, float Zins); void Add_Zins(Konto &Kto); //Addiere monatlichen Zinsbetrag void Einzahlung(Konto &Kto, float Betrag); //Addiere Einzahlungsbetrag void Auszahlung(Konto &Kto, float Betrag); //Subtrahiere Rckzahlungsbetrag float Kontostand(Konto Kto); //Kontostand wird ermittelt. Funktionen, die sich auf den Typ Konto beziehen. #include <iostream.h> //Struktur eines Kontos struct Konto { float Stand; float Zinssatz; ; //Prototypen void Initialisieren(Konto &Kto, float Stand, float Zins); void Add_Zins(Konto &Kto); //Addiere monatlichen Zinsbetrag void Einzahlung(Konto &Kto, float Betrag); //Addiere Einzahlungsbetrag void Auszahlung(Konto &Kto, float Betrag); //Subtrahiere Rckzahlungsbetrag float Kontostand(Konto Kto); //Kontostand wird ermittelt. int main(void) { Konto Kto1, Kto2; //2 Konten //Initialisieren und Addieren des Zinsbetrags Initialisieren(Kto1, 1000, 10); Add_Zins(Kto1); cout.setf(ios::fixed, ios::floatfield); cout.precision( 2 ); cout<<"\nder Kontostand Kto1: DM "<<Kontostand(Kto1)<<endl; //Versuch, die Kontost nde direkt zu ndern Kto1.Stand = 100000;
Programmierkurs C++ Kapitel 7:Objektorientierte Programmierung Seite 3 Kto2.Stand = Kto1.Stand; //Ausgabe der Kontost nde cout<<"\n neuer Kontostand Kto1: DM "<<Kontostand(Kto1); cout<<"\n neuer Kontostand Kto2: DM "<<Kontostand(Kto2)<<endl; return 0; //Initialiiseren der Datenstruktur void Initialisieren(Konto &Kto, float Stand, float Zins) { Kto.Stand=Stand; Kto.Zinssatz=Zins; //Berechne und Addiere monatlichen Zinsbetrag void Add_Zins(Konto &Kto) { Kto.Stand += Kto.Stand * Kto.Zinssatz /12/100; //Addiere Einzahlungsbetrag void Einzahlung(Konto &Kto, float Betrag) { Kto.Stand += Betrag; //Subtrahiere Auszahlungsbetrag void Auszahlung(Konto &Kto, float Betrag) { Kto.Stand -= Betrag; //Ermittle Kontostand float Kontostand(Konto Kto) { return Kto.Stand; Der Objektorientierte Ansatz //Konto.cpp: Das Programm realisiert eine einfache Kontoverwaltung. //Es benutzt die Möglichkeiten der Datenkapselung //("Information hiding"), die innerhalb des Klassenkozeptes zur //Verfügung stehen. K t o 1 Datentyp Konto (als Klasse) Interface nach außen Konto(float Stand, float Zins); //Konstruktor, Initialisierung void Add_Zins(); //Addiere monatlichen Zinsbetrag void Einzahlung(float Betrag); //Addiere Einzahlungsbetrag void Auszahlung(float Betrag); //Subtrahiere Rückzahlungsbetrag float Kontostand(); //Kontostand wird ermittelt. private: float Stand; float Zinssatz;
Programmierkurs C++ Kapitel 7:Objektorientierte Programmierung Seite 4 #include <iostream.h> //Deklaration der Klasse Konto class Konto { Konto(float Stand, float Zins); //Konstruktor, Initialisierung void Add_Zins(); //Addiere monatlichen Zinsbetrag void Einzahlung(float Betrag); //Addiere Einzahlungsbetrag void Auszahlung(float Betrag); //Subtrahiere Rückzahlungsbetrag float Kontostand(); //Kontostand wird ermittelt. private: float Stand; float Zinssatz; ; int main(void) { Konto Kto1(1000,10), Kto2(0,12); 2 Objekte werden definiert! //2 Konten mit Argumenten für den //Konstruktor. //Zinsaktualisierung für Kto1 Kto1.Add_Zins(); Bezug auf ein Objekt cout.setf(ios::fixed, ios::floatfield); cout.precision( 2 ); cout<<"\nder Kontostand Kto1: DM "<< Kto1.Kontostand() <<" \n"; //Versuch, die Kontostände direkt zu ändern //Kto1.Stand = 100000; nicht zulässig! //Kto2.Stand = Kto1.Stand; nicht zulässig! //stattdessen Kto1.Einzahlung(1000); Kto2.Einzahlung(1500); Kto1.Auszahlung(300); //Ausgabe der Kontostände cout<<"\n neuer Kontostand Kto1: DM "<<Kto1.Kontostand(); cout<<"\n neuer Kontostand Kto2: DM "<<Kto2.Kontostand(); return 0; //Initialiiseren der Datenstruktur Konto::Konto(float Stand, float Zins) { this->stand=stand; Zinssatz=Zins; //Berechne und Addiere monatlichen Zinsbetrag void Konto::Add_Zins() { Stand += Stand * Zinssatz /12/100; //Addiere Einzahlungsbetrag void Konto::Einzahlung(float Betrag) { Stand += Betrag;
Programmierkurs C++ Kapitel 7:Objektorientierte Programmierung Seite 5 //Subtrahiere Auszahlungsbetrag void Konto::Auszahlung(float Betrag) { Stand -= Betrag; //Ermittle Kontostand float Konto::Kontostand() { return Stand; Das Programm wird aufgeräumt: Header-Datei Konto.h //Deklaration der Klasse Konto class Konto { Konto(float Stand, float Zins); //Konstruktor, Initialisierung void Add_Zins(); //Addiere monatlichen Zinsbetrag void Einzahlung(float Betrag); //Addiere Einzahlungsbetrag void Auszahlung(float Betrag); //Subtrahiere Rückzahlungsbetrag float Kontostand(); //Kontostand wird ermittelt. private: float Stand; float Zinssatz; ; Eigene Moduldatei Kontodef.cpp #include "Konto.h" //Initialisieren der Datenstruktur Konto::Konto(float Stand, float Zins) { this->stand=stand; Zinssatz=Zins; //Berechne und Addiere monatlichen Zinsbetrag void Konto::Add_Zins() { Stand += Stand * Zinssatz /12/100; //Addiere Einzahlungsbetrag void Konto::Einzahlung(float Betrag) { Stand += Betrag; //Subtrahiere Auszahlungsbetrag void Konto::Auszahlung(float Betrag) { Stand -= Betrag; //Ermittle Kontostand float Konto::Kontostand() { return Stand;
Programmierkurs C++ Kapitel 7:Objektorientierte Programmierung Seite 6 Die Datei für die Anwendung Konto.cpp #include <iostream.h> #include "Konto.h" int main(void) { Konto Kto1(1000,10), Kto2(0,12); //2 Konten mit Argumenten für den //Konstruktor. //Zinsaktualisierung für Kto1 Kto1.Add_Zins(); cout.setf(ios::fixed, ios::floatfield); cout.precision( 2 ); cout<<"\nder Kontostand Kto1: DM "<< Kto1.Kontostand() <<" \n"; //Versuch, die Kontostände direkt zu ändern //Kto1.Stand = 100000; nicht zulässig! //Kto2.Stand = Kto1.Stand; nicht zulässig! //stattdessen Kto1.Einzahlung(1000); Kto2.Einzahlung(1500); Kto1.Auszahlung(300); //Ausgabe der Kontostände cout<<"\n neuer Kontostand Kto1: DM "<<Kto1.Kontostand(); cout<<"\n neuer Kontostand Kto2: DM "<<Kto2.Kontostand(); return 0; Durch Hinzufügen von Konto.h und Kontodef.cpp (bzw. Kontodef.obj) kann man in der Anwendung Objekte der Klasse Konto verwenden (andere Sprechweise: Objekte vom Typ Konto). Konstruktor, Destruktor Der Konstruktor ist eine Funktion, die nach der Erstellung eines Objektes automatisch aufgerufen wird. Der Destruktor ist eine Funktion, die beim Ende des Objektes automatisch aufgerufen wird. Syntax: Der Konstruktor hat den Namen der Klasse, er kann Argumente haben, jedoch keinen Funktionswert (nicht einmal void). Die Argumente werden mit der Erstellanweisung des Objektes angegeben, d.h. bei der Definition des Objektes oder bei der new-anweisung. Der Destruktor hat den Namen der Klasse mit vorgesetzter Tilde ~. Der Destruktor hat keine Argumente und keinen Funktionswert. class Klasse1 {
Programmierkurs C++ Kapitel 7:Objektorientierte Programmierung Seite 7 Klasse1(int, int, float); //Konstruktor...... ~Klasse1(); //Destruktor... ; //Definition des Konstruktors Klasse1::Klasse1( int i1, int i2, float f2) {...... //Definition des Destruktors Klasse1::~Klasse1( void ) {...... int main(void) { Klasse1 Objekt1(2, 44, 7.12 ); //Definition des Objektes Objekt1 mit den Konstruktorargumenten Klasse1 Objekt22( 2, 45, 1.0 ); Klasse1 * pobjekt33; pobjekt33 = new Klasse1(3, 46, 2.1 ); //dynamische Erstellung des Objektes *pobjekt33 mit // Konstruktorargumenten delete pobjekt33; //Entfernen des Objektes *pobjekt33, impl Aufruf des Destruktors //Beim return impliziter Aufruf des Destruktors für Objekt1 und Objekt22. Der this -Zeiger Die Klasse definiert Namen von Daten und Funktionen (Methoden). Diese Namen sind global zu den einzelnen Methoden. Zur Vermeidung von Mehrdeutigkeiten gibt es den Zeiger this. Er zeigt auf das Objekt, innerhalb dessen gerade die Methoden der Klasse ablaufen. z.b. in der Klasse Bank_Konto ist die Varialble Stand definiert. Ein Bezug auf diese Variable innerhalb einer Methode kann über this -> Stand geschehen. Ist die Eindeutigkeit gegeben, kann man natürlich einfacher Stand verwenden. Nachrichten, Methodenaufrufe Eine Nachricht an ein Objekt ist der Aufruf einer Methode (Funktion) der Klasse. Senden einer Nachricht über den Funktionsnamen: <Objektname>.<Funktionsname> (Argumentliste) Senden einer Nachricht über einen Zeiger auf das Objekt:
Programmierkurs C++ Kapitel 7:Objektorientierte Programmierung Seite 8 <Objektzeiger> -> <Funktionsname> (Argumentliste) Das Aussehen einer OOP Programmkonstruktion Klassenheaderdatei (.h) #include Anwendung Implementierungsdatei(en) (.cpp ) der Klassenfunktionen (Methoden) (.cpp ) Vererbung Was? Vererbung ist die Eigenschaft der OOP, die es einer Klasse, genannt die abgeleitete Klasse, erlaubt, die Struktur und das Verhalten mit einer anderen Klasse, genannt die Basisklasse, zu teilen. Die abgeleitete Klasse erbt die Struktur und das Verhalten der Basisklasse. Warum? Man kann Programmcode von anderen Projekten wiederverwenden. Es muß nicht jedesmal das Rad neu erfunden werden. Wichtig ist, daß beim Vererben die Basisklasse modifiziert werden kann. Man kann dazu sogar Klassenhierarchien erstellen. Beispiel: Unsere Klasse Bank_Konto Bank_Konto Basisklasse
Programmierkurs C++ Kapitel 7:Objektorientierte Programmierung Seite 9 Scheck_Konto Spar_Konto abgeleitete Klasse abgeleitete Klasse Super_Konto abgeleitete Klasse Basisklasse Konto //Deklaration der Basisklasse Bank_Konto class Bank_Konto { void Einzahlen(float Betrag); int Konto_Num(); float Aktueller_Stand(); protected: int Nummer; float Stand; ; //Einzahlung wird verbucht //Kontonummer wird ermittelt //Aktueller Kontostand //Kontonummer //Kontostand protected: wie private, jedoch können sich die abgeleiteten Klassen auf diese Größen beziehen. In den abgeleiteten Klassen sind sie private. Die abgeleitete Klasse Scheck_Konto //Deklaration der abgeleiteten Klasse Scheck_Konto class Scheck_Konto : public Bank_Konto { Scheck_Konto(int Kto_Num = 0000, //Konstruktor float Stnd=0, float Min=1000, float Geb=0.5); void Scheck_Einlsn(float Betr); //Scheckeinlösen ; protected: float Minimum; float Gebuehr; //Minimaler Kontostand zur Scheckeinlösung //Einlösegebühr pro Scheck Die Klasse Super_Konto //Deklaration der abgeleiteten Klasse Super_Konto class Super_Konto: public Scheck_Konto { Super_Konto(int Kto_Nr = 0000, float Stnd=0, float Min=1000, float Geb=0.5, //Konstruktor float Zinsstz=12); void Add_Zins(); //Addiere Zins
Programmierkurs C++ Kapitel 7:Objektorientierte Programmierung Seite 10 ; protected: float Zins_Satz; //Jährlicher Zinssatz Die Klasse Spar_Konto //Abgeleitete Klasse Spar_Konto class Spar_Konto: public Bank_Konto { Spar_Konto(int Kto_Nr=0000, //Konstruktor float Stnd=0, float Zinsstz=12.0); void Add_Zins(); //Addiere Zinsbetrag void Abheben(float Betrg); //Subtrahiere Betrag der Abhebung ; protected: float Zins_Satz;