Programmieren 1 - Strukturen - Klassen - Objekte
Programmieren 1 - Strukturen - Klassen - Objekte
Programmieren 1 - Strukturen - Klassen - Objekte
Erfolgreiche ePaper selbst erstellen
Machen Sie aus Ihren PDF Publikationen ein blätterbares Flipbook mit unserer einzigartigen Google optimierten e-Paper Software.
FB Informatik<br />
Prof. Dr. R.Nitsch<br />
<strong>Programmieren</strong> 1 - <strong>Strukturen</strong> - <strong>Klassen</strong> - <strong>Objekte</strong><br />
‣ Funktionsabstraktion vs Datenabstraktion<br />
‣ Abstrakter Datentyp<br />
‣ <strong>Klassen</strong> – <strong>Objekte</strong><br />
‣ UML Einführung<br />
‣ Pass by value – Pass by reference<br />
‣ Prinzip des kleinsten Privilegs (const-correctness)<br />
‣ Copy-Konstruktor
Funktionsorientierte Programmierung (Veraltet)<br />
FB Informatik<br />
Prof. Dr. R.Nitsch<br />
// Fraction.h<br />
#pragma once<br />
struct Fraction {<br />
int z,n;<br />
};<br />
Fraction add(Fraction op1, Fraction op2);<br />
Fraction subtract(Fraction op1, Fraction op2);<br />
// …<br />
Domäne des Systemprogrammierers<br />
Domäne des Anwendungsprogrammierers<br />
// Anwendung: Rechnen mit Brüchen<br />
#include "Fraction.h"<br />
int main() {<br />
Fraction frac1, frac2, sum;<br />
frac1.z=1; frac1.n=2; // kein Zugriffsschutz<br />
frac2=set(frac2,3,4);<br />
sum=add(frac1,frac2);<br />
// …<br />
// Fraction.cpp<br />
#include "Fraction.h"<br />
Fraction add(Fraction op1, Fraction op2) {<br />
if(op1.n==0||op2.n==0) // PRE<br />
exit(1); // aborts program<br />
Fraction result;<br />
result.z = op1.z*op2.n+op1.n*op2.z;<br />
result.n = op1.n*op2.n;<br />
return result;<br />
}<br />
Fraction subtract(Fraction op1, Fraction op2)<br />
{ /* … */ }<br />
// …<br />
Fraction set(Fraction op,int num, int denom)<br />
if(denom==0) exit(1); // PRE<br />
op.z=num; op.n=denom;<br />
return op;<br />
}<br />
Versuch einer kontrollierten Zustandsänderung<br />
- umständlich (3 Parameter)<br />
- unverbindlich (direkter Zugriff möglich)<br />
22.04.2013 2
Funktionsorientierte Programmierung und ihre Nachteile<br />
FB Informatik<br />
Prof. Dr. R.Nitsch<br />
Funktionsabstraktion<br />
Bruch-Anwendung aus Praktikum-Aufgabe 2 ist ein Beispiel dafür<br />
Merkmale: Programmstrukturierungsmittel sind Daten zur Zustandsspeicherung und<br />
getrennt davon die auf sie angewendeten Funktionen.<br />
Nachteile:<br />
‣Daten können ohne Initialisierung benutzt werden<br />
‣Daten können falsch initialisiert sein. Ausschließlich der Programmierer ist verantwortlich.<br />
‣Daten müssen den Funktionen übergeben werden.<br />
‣Daten und Funktionen können beliebig im Programm verteilt sein (schlecht für Fehlersuche,<br />
Wiederverwendung, Änderungen)<br />
‣Bei Änderungen in der Datenstruktur (z.B. andere Bezeichner, Datentypen oder Codierung)<br />
müssen alle Anwendungsprogramme, die diesen benutzerdefinierten Typ benutzen, geändert<br />
werden.<br />
Abhilfe: Datenabstraktion (Abstrakter Datentyp, Klasse, Datenkapselung)<br />
22.04.2013 3
Datenabstraktion<br />
FB Informatik<br />
Prof. Dr. R.Nitsch<br />
Deshalb neues Programm-Strukturierungskonzept: Datenabstraktion<br />
‣Daten stehen im Mittelpunkt;<br />
‣Sie haben eigene Funktionen zur Verfügung, die Methoden genannt werden.<br />
‣Daten und zugehörige Funktionen werden an einer Stelle im Programm zusammen gefasst.<br />
Daraus resultiert eine bessere Pflegbarkeit, Wiederverwendbarkeit und einfachere<br />
Fehlereingrenzung.<br />
‣Nur diese Methoden haben Zugriff auf die Daten (Datenkapselung, Zugriffsschutz).<br />
‣Welche Daten (Anzahl, Typ, …) den Objektzustand beschreiben, bleibt dem Anwender<br />
verborgen (Datenabstraktion)<br />
‣Datentypen mit diesen Eigenschaften<br />
nennt man Abstrakte Datentypen (ADT)<br />
Abstrakter Datentyp =<br />
Daten + Funktionen<br />
Botschaft<br />
z<br />
n<br />
‣Anforderung:<br />
Die Programmiersprache muss<br />
diesen Datentyp unterstützen.<br />
‣C++ tut dies in Form von userdefinierten<br />
<strong>Klassen</strong>.<br />
set(zaehler,nenner)<br />
gekapselte Daten<br />
Abstrakter Datentyp<br />
22.04.2013 4
Funktionsorientiert versus Objektorientiert<br />
FB Informatik<br />
Prof. Dr. R.Nitsch<br />
// Fraction.h<br />
#pragma once<br />
struct Fraction {<br />
int z,n;<br />
};<br />
Fraction add(Fraction op1, Fraction op2);<br />
Fraction subtract(Fraction op1, Fraction op2);<br />
// …<br />
// Anwendung: Rechnen mit Brüchen<br />
#include "Fraction.h"<br />
<strong>Klassen</strong>deklaration<br />
int main() {<br />
Fraction frac1, frac2, sum;<br />
frac1.z=1; frac1.n=2; // kein Zugriffsschutz<br />
frac2=set(frac2,3,4);<br />
sum=add(frac1,frac2);<br />
// …<br />
// Fraction.h<br />
#pragma once<br />
class Fraction {<br />
int z;<br />
int n;<br />
public:<br />
Fraction add(Fraction op2);<br />
Fraction subtract(Fraction op2);<br />
// …<br />
};<br />
// Anwendung: Rechnen mit Brüchen<br />
#include "Fraction.h"<br />
int main() {<br />
Fraction frac1(1,2), frac2(3,4);<br />
Fraction sum; // Standardkonstruktoraufruf<br />
frac1.n=0;<br />
sum=frac1.add(frac2);<br />
// …<br />
Membervariable, Atrribut<br />
Alle Funktionen, die Zugriff auf<br />
Membervariable haben sollen,<br />
(Memberfunktionen) müssen in<br />
der <strong>Klassen</strong>deklaration stehen.<br />
Memberfunktion, Methode<br />
Objektdefinition mit gleichzeitiger<br />
Initialisierung durch<br />
Konstruktor<br />
Geht jetzt nicht mehr! Alle Membervariablen<br />
sind vor Fremdzugriff<br />
geschützt (Datenkapselung)<br />
Anwender muss die interne Aufrufendes Objekt (Operand 1) Memberfunktionsaufruf mittels '.'-Operator<br />
Datenstruktur der Fraction- Muss jetzt nicht mehr in der<br />
<strong>Objekte</strong> kennen! (keine Datenkapselung)<br />
Parameterliste stehen, sondern<br />
<br />
wird immer übergeben, aber nicht<br />
als Kopie sondern als Orginal<br />
22.04.2013 5
Funktionsorientiert versus Objektorientiert<br />
FB Informatik<br />
Prof. Dr. R.Nitsch<br />
// Fraction.cpp<br />
#include "Fraction.h"<br />
Fraction add(Fraction op1, Fraction op2) {<br />
if(op1.n==0||op2.n==0) // PRE<br />
exit(1); // aborts program<br />
Fraction result;<br />
result.z = op1.z*op2.n+op1.n*op2.z;<br />
result.n = op1.n*op2.n;<br />
return result;<br />
}<br />
Fraction subtract(Fraction op1, Fraction op2)<br />
{ /* … */ }<br />
// …<br />
// Fraction.cpp<br />
#include "Fraction.h"<br />
Fraction Fraction::add(Fraction op2) {<br />
if(n==0||op2.n==0) // PRE<br />
exit(1); // aborts program<br />
Fraction result;<br />
result.z = z*op2.n+n*op2.z;<br />
}<br />
result.n = n*op2.n;<br />
return result;<br />
Fraction Fraction::subtract(Fraction op2)<br />
{ /* … */ }<br />
// …<br />
Deklariert Zugehörigkeit zum<br />
Namensbereich "Fraction"<br />
Membervariable des<br />
aufrufenden Objekts<br />
Fraction set(Fraction op,int num, int denom)<br />
if(denom==0) exit(1); // PRE<br />
op.z=num; op.n=denom;<br />
return op;<br />
}<br />
void Fraction::set(int num, int denom)<br />
if(denom==0) exit(1); // PRE<br />
z=num; n=denom;<br />
return;<br />
Hier wird die Membervariable des<br />
}<br />
aufrufenden Objekts und nicht die<br />
einer Kopie desselben verändert.<br />
Rückgabe an Aufrufstelle und dort<br />
Zuweisung an Original sind deshalb<br />
nicht mehr nötig.<br />
22.04.2013 6
Funktionsorientiert versus Objektorientiert<br />
FB Informatik<br />
Prof. Dr. R.Nitsch<br />
// Fraction.cpp // Fortsetzung Fraction.cpp<br />
// Konstruktoren<br />
Hier gibt es nichts Vergleichbares!<br />
Fraction::Fraction() {<br />
z=0; n=1;<br />
Konstruktoren<br />
}<br />
Name = <strong>Klassen</strong>name<br />
Haben keinen Rückgabetyp.<br />
Fraction::Fraction( int num, int denom)<br />
if(denom==0) // PRE<br />
exit(1); // aborts program<br />
z=num; n=denom;<br />
}<br />
Membervariable des neu<br />
erzeugten Objekts<br />
Fraction::~Fraction()<br />
{<br />
Destruktor<br />
}<br />
Wird automatisch beim Verlassen des<br />
Gültigkeitsbereiches aufgerufen.<br />
Zuständig für Aufräumarbeiten.<br />
Hat hier nichts zu tun.<br />
22.04.2013 7
<strong>Objekte</strong> im Speicher<br />
FB Informatik<br />
Prof. Dr. R.Nitsch<br />
Jedes Objekt besitzt seine eigenen<br />
Membervariablen<br />
Speicherplatz für Membervariable wird erst<br />
bei der Objektdefinition reserviert.<br />
Memberfunktionen gibt es nur einmal pro<br />
Klasse im Speicher<br />
Das aufrufende Objekt wird den Memberfunktionen<br />
stets automatisch übergeben.<br />
Über den Membervariablennamen können die<br />
Memberfunktionen direkt lesend und<br />
schreibend auf die Membervariablen des<br />
aufrufenden Objekts zugreifen.<br />
Durch ein abschließendes const in der<br />
Deklaration einer Memberfunktion kann man<br />
dieser das Schreibrecht für die Membervariablen<br />
des aufrufenden Objekts<br />
entziehen.<br />
Objekt frac1<br />
Objekt frac2<br />
z<br />
n<br />
…<br />
z<br />
n<br />
…<br />
Adresse<br />
C000<br />
C100<br />
Read-only Memberfunktion<br />
Fraction Fraction::add(Fraction op2) const {<br />
Fraction result;<br />
z = z*op2.n+n*op2.z;<br />
Geht nicht, weil Membervariablen<br />
des aufrufen-<br />
n = n*op2.n;<br />
result.z = z*op2.n+n*op2.z;<br />
den Objekts nun vor Veränderung<br />
geschützt sind.<br />
result.n = n*op2.n;<br />
return result;<br />
}<br />
OK, weil hier nicht die<br />
Membervariablen des<br />
aufrufenden Objekts<br />
geändert werden.<br />
22.04.2013 8
Unified Modelling Language (UML)<br />
FB Informatik<br />
Prof. Dr. R.Nitsch<br />
ermöglicht programmiersprachenunabhängige<br />
‣Spezifikation<br />
‣Visualisierung<br />
‣Konstruktion<br />
‣Dokumentation<br />
objektorientierter Softwaresysteme<br />
UML-<strong>Klassen</strong>diagramm<br />
a) niedrigster Detaillierungsgrad<br />
Fraction<br />
Klasse<br />
frac2<br />
Objekt<br />
UML kennt keine strenge visuelle Unterscheidung<br />
zwischen <strong>Objekte</strong>n und <strong>Klassen</strong>. Objektnamen sind<br />
unterstrichen, <strong>Klassen</strong>namen nicht.<br />
b) mittlerer Detaillierungsgrad<br />
Fraction<br />
-z_: int<br />
- n_: int<br />
<strong>Klassen</strong>name<br />
Attribute oder Membervariable<br />
+ Fraction()<br />
+ ~Fraction()<br />
+ add(op2:Fraction):Fraction<br />
+ cancelDown():void<br />
+ …<br />
Methoden oder Memberfktn.<br />
'+' bzw. '-' bedeutet public- bzw. private-<br />
Deklaration. Dies hat Auswirkung auf die<br />
Sichtbarkeit (kommt gleich)<br />
22.04.2013 9
Pseudocode-Notation für Algorithmen<br />
FB Informatik<br />
Prof. Dr. R.Nitsch<br />
Pseudocode<br />
‣ soll das Wesentliche eines Algorithmus programmiersprachenunabhängig veranschaulichen<br />
‣ verdeckt viele Implementierungsdetails<br />
‣ soll intuitiv und leicht zu verstehen sein<br />
‣ besteht aus Kontroll- und Schlüsselwörtern (meist in Englisch) und natürlicher Sprache<br />
Beispiele für häufig verwendete Notationen<br />
Module<br />
program Programmname ... end Programmname<br />
klasse <strong>Klassen</strong>name { ... }<br />
Kommentare<br />
// kommentar<br />
# kommentar<br />
/* kommentar */<br />
Auswahl<br />
if ... then ... else ... end if<br />
if ... then ... fi<br />
if ... then ... else ... fi<br />
Anwendungsbeispiele<br />
Schleifen<br />
while Bedingung do ... od /* abweisend */<br />
repeat ... until Abbruchbedingung /* annehmend */<br />
for Bereichsanfang to Bereichsende step Schrittweite do … od<br />
Definition von Funktionen<br />
function Name ( Parameter ) ... end Name<br />
Zusicherungen<br />
assert …<br />
function gcd(a,b)<br />
// gibt größten gemeinsamen Teiler zurück<br />
assert a>0; assert b>0; assert a0 or b mod try>0 do<br />
try := try – 1<br />
od<br />
if Ampel rot oder gelb then<br />
stoppe<br />
else<br />
fahre weiter<br />
return try<br />
fi22.04.2013 end gcd<br />
10
Praktikumsaufgabe 2: string toString(int)<br />
FB Informatik<br />
Prof. Dr. R.Nitsch<br />
Algorithmus in Pseudocode<br />
Rohfassung (umgangssprachlich, weniger präzise) Verfeinerung ( präziser )<br />
Algorithmus zur Umwandlung einer Ganzzahl n<br />
in eine Zeichenkette s<br />
falls n=0 gib "0" zurück<br />
bestimme und merke Vorzeichen vz<br />
erzeuge eine leere Zeichenkette s<br />
mache n positiv<br />
jetzt ist n positiv<br />
solange n > 0<br />
führe aus<br />
bestimme Einerstelle e von n<br />
erzeuge das e repräsentierende Zeichen z<br />
verkette das Zeichen z mit s<br />
streiche die Einerstelle in n<br />
verkette vz und s<br />
gib s zurück<br />
function toString(n) -> s<br />
// wandelt Zahl n in Zeichenkette s um<br />
// Eingabe: Ganzzahl n<br />
// Ausgabe: Zeichenkette s<br />
if n=0 then return "0" fi<br />
if n0 do<br />
einer := n mod 10<br />
ascii := ASCII-Code von einer<br />
Typumwandlung ascii -> z<br />
s := z + s<br />
n := n/10 /* Ganzzahldivision! */<br />
od<br />
s := vz + s<br />
return s<br />
22.04.2013 11
Praktikumsaufgabe 2: int get_int(string prompt, int min, int max)<br />
FB Informatik<br />
Prof. Dr. R.Nitsch<br />
Algorithmus in Pseudocode<br />
function get_int(prompt,min,max) -> n<br />
// Einlesen einer Ganzzahl n im Bereich min
Hörsaalübung "Eine Motorbootfahrt mit C++"<br />
FB Informatik<br />
Prof. Dr. R.Nitsch<br />
// Zweck: Beispielanwendung "Motorboat"<br />
// Datei: MotorboatApp.cpp<br />
#include "Motorboat.h"<br />
int main(void) {<br />
Motorboat elsa; // Konstruktor<br />
elsa.howDoYouDo();<br />
elsa.castOff();<br />
elsa.howDoYouDo();<br />
elsa.faster(5);<br />
elsa.howDoYouDo();<br />
elsa.stop();<br />
elsa.howDoYouDo();<br />
elsa.dock();<br />
elsa.howDoYouDo();<br />
}<br />
// Motorboat.h: Schnittstellendeklaration.<br />
#pragma once<br />
class Motorboat {<br />
int speed_;<br />
bool isCastOff_;<br />
public:<br />
Motorboat();<br />
~Motorboat();<br />
void howDoYouDo();<br />
void castOff();<br />
void faster( int soMuch );<br />
void stop();<br />
void dock();<br />
};<br />
Motorboat<br />
- isCastOff_:bool = true<br />
- speed_:int = 0<br />
+ Motorboat()<br />
+ ~Motorboat()<br />
+ castOff():void<br />
+ howDoYouDo():void<br />
+ faster(soMuch:int):void<br />
+ dock():void<br />
22.04.2013<br />
+ stop():void<br />
13
Hörsaalübung "Eine Motorbootfahrt mit C++"<br />
FB Informatik<br />
Prof. Dr. R.Nitsch<br />
// Motorboot.cpp: Implementation.<br />
#include "Motorboot.h"<br />
#include <br />
#include <br />
using namespace std;<br />
Motorboat::Motorboat() {<br />
isCastOff_ = false;<br />
speed_ = 0;<br />
cout
Hörsaalübung "Eine Motorbootfahrt mit C++"<br />
FB Informatik<br />
Prof. Dr. R.Nitsch<br />
void Motorboat::faster(int soMuch)<br />
{<br />
if ( soMuch
Struktur und Syntax einfacher OO-Programme in C++<br />
FB Informatik<br />
Prof. Dr. R.Nitsch<br />
1 Systemprogrammierung, Teil 1: <strong>Klassen</strong>deklaration<br />
(Schnittstellenbeschreibung; enthält Prototypen)<br />
// Datei: NeueKlasse.h<br />
class NeueKlasse {<br />
private:<br />
attribut1;<br />
attribut2;<br />
...<br />
attributN;<br />
public:<br />
NeueKlasse();<br />
~NeueKlasse();<br />
methode1();<br />
methode2();<br />
...<br />
methodeM();<br />
};<br />
22.04.2013<br />
Privater Schnittstellenteil (default: private)<br />
Zugriffsschutz von aussen<br />
keine Speicherplatzreservierung,<br />
nur Bauplan<br />
// öffentlicher (public) Schnittstellenteil beginnt hier<br />
// Konstruktor: Kein Ergebnistyp; wird vom System auch<br />
// automatisch erzeugt.<br />
// Destruktor: Kein Ergebnistyp,<br />
// wird automatisch aufgerufen<br />
Counter<br />
- value_: int<br />
+ <br />
+ Destruktor<br />
+ set(int): void<br />
+ higher(): void<br />
+ lower(): void<br />
+ show(): void<br />
{0≤value≤10}<br />
// File: Counter.h<br />
// Class-Declaration<br />
class Counter {<br />
private:<br />
int value_;<br />
public:<br />
Counter();<br />
~Counter();<br />
void set(int);<br />
void higher();<br />
void lower();<br />
void show();<br />
};
Struktur und Syntax einfacher OO-Programme in C++<br />
FB Informatik<br />
Prof. Dr. R.Nitsch<br />
2 Anwendungsprogrammierung:<br />
Arbeiten mit problemangepassten Datentypen und <strong>Objekte</strong>n<br />
// Datei: main.cpp<br />
#include "NeueKlasse.h"<br />
void main(void)<br />
{<br />
NeueKlasse einObjekt;<br />
NeueKlasse einAnderesObjekt;<br />
einObjekt.methode1();<br />
einObjekt.methode2();<br />
einAnderesObjekt.methode1();<br />
}<br />
// Hier werden die Destruktoren automatisch aufgerufen<br />
// Methode1 arbeitet mit den Membervariablen von einObjekt<br />
// Methode1 arbeitet mit den Membervar von einAnderesObjekt<br />
// Std-Konstruktoraufruf; Achtung: ohne "( )"<br />
// hier wird Objekt namens "einObjekt" definiert<br />
// Memberfunktionen gibt es nur einmal<br />
// pro Klasse im Speicher<br />
// Datei: main.cpp<br />
#include "Counter.h"<br />
int main(void) {<br />
Counter myCounter;<br />
myCounter.higher();<br />
myCounter.show();<br />
myCounter.lower();<br />
myCounter.show();<br />
Counter yourCounter();<br />
yourCounter.show();<br />
int i=yourCounter.value_;<br />
return 0;<br />
}<br />
22.04.2013 //Fehler: Zugriffschutz 17
Struktur und Syntax einfacher OO-Programme in C++<br />
FB Informatik<br />
Prof. Dr. R.Nitsch<br />
3 Systemprogrammierung, Teil 2: <strong>Klassen</strong>definition (Implementierung der Methoden)<br />
// Datei: NewClass.cpp<br />
#include " NeueKlasse.h"<br />
NeueKlasse::NeueKlasse(){<br />
[]<br />
}<br />
NeueKlasse::~NeueKlasse() {<br />
[]<br />
Bezeichner (Name)<br />
}<br />
Namensbereich der Methode<br />
NeueKlasse::methode1(){<br />
<br />
Namensbereichauswahloperator<br />
...<br />
<br />
}<br />
...<br />
// File: Counter.cpp<br />
// Class-Implementation<br />
#include "Counter.h"<br />
#include <br />
using namespace std;<br />
Counter::Counter() { // Konstruktor<br />
value_ = 0;<br />
cout
Ein einfaches Beispiel - Datentyp Counter<br />
FB Informatik<br />
Prof. Dr. R.Nitsch<br />
Counter<br />
- value: int<br />
+ Konstruktor<br />
+ Destruktor<br />
+ higher():void<br />
+ lower(): void<br />
+ show(): void<br />
// Datei: main,cpp<br />
#include "Counter.h"<br />
int main(void) {<br />
Counter myCounter;<br />
myCounter.higher();<br />
myCounter.show();<br />
myCounter.lower();<br />
myCounter.show();<br />
// File: Counter.h<br />
// Class-Declaration<br />
class Counter{<br />
private:<br />
int value_;<br />
public:<br />
Counter();<br />
~ Counter();<br />
void higher();<br />
void lower();<br />
void show();<br />
};<br />
// File: Counter.cpp<br />
// Class-Implementation<br />
#include "Counter.h"<br />
#include <br />
using namespace std;<br />
Counter::Counter() { // Konstruktor<br />
value_ = 0;<br />
cout
Memberfunktionen mit Parametern<br />
FB Informatik<br />
Prof. Dr. R.Nitsch<br />
Funktionserweiterung: Zähler auf bestimmten Wert setzen<br />
// Datei: main,cpp<br />
#include "Counter.h"<br />
int main(void) {<br />
Counter myCounter;<br />
myCounter.set(10); //10 -> myCounter.value<br />
myCounter.show();<br />
}<br />
Counter yourCounter();<br />
yourCounter.set(5); //10 -> yourCounter.value<br />
yourCounter.show();<br />
return 0;<br />
// File: Counter.h<br />
// Class-Declaration<br />
class Counter<br />
{<br />
private:<br />
int value_;<br />
public:<br />
// … ommitted<br />
void set( int init );<br />
};<br />
Kopie<br />
// File: Counter.cpp<br />
// Class-Implementation<br />
// … ommitted<br />
myCounter::value_<br />
yourCounter::value_<br />
Counter::set( int init ) {<br />
//PRE: 0
Überladene Methoden/Funktionen<br />
FB Informatik<br />
Prof. Dr. R.Nitsch<br />
sind mehrere Methoden/Funktionen mit gleichem Namen, aber<br />
unterschiedlichem Parameterprofil (= Signatur)<br />
Parameterprofil ist bestimmt durch Anzahl, Typ und Reihenfolge der Parameter.<br />
Achtung: Der Rückgabetyp gehört nicht dazu!<br />
Beispiel<br />
//Deklaration<br />
class Counter {<br />
int value_;<br />
public:<br />
Counter();<br />
Counter(int);<br />
void higher();<br />
void higher(int);<br />
…<br />
};<br />
int<br />
higher(int);<br />
überladene Memberfunktionen<br />
ruft auf<br />
Fehler:<br />
Hat gleiche Signatur<br />
wie void higher(int)<br />
Auswahl durch Compiler;<br />
in Zusammenhang mit<br />
Typkonvertierung diejenige,<br />
die am besten passt.<br />
//Anwendung<br />
void main() {<br />
Counter c1, c2(5);<br />
c1.higher();<br />
c2.higher(5);<br />
}<br />
//Impementation<br />
void Counter::higher() { value_ = (value_
<strong>Objekte</strong> als Parameter<br />
Beispiel<br />
//Deklaration<br />
class Counter<br />
{<br />
int value_;<br />
public:<br />
// Konstruktoren<br />
void higher();<br />
void higher(int);<br />
void higher(Counter);<br />
};<br />
überladene Memberfunktionen<br />
Objekt als<br />
Parameter!<br />
//Implementation<br />
void Counter::Counter() { /* … */ }<br />
void Counter::Counter( int v ) {/* … */}<br />
void Counter::higher() {/* … */}<br />
void Counter::higher( int soViel ) {/* … */}<br />
19.04.2012<br />
//Anwendung<br />
void main() {<br />
Counter c1, c2(10);<br />
c1.higher( c2 );<br />
}<br />
ruft auf<br />
Was ist hier falsch?<br />
FB Informatik<br />
Prof. Dr. R.Nitsch<br />
Aktion?<br />
Copy-Konstruktor<br />
wird implizit aufgerufen,<br />
um Kopie auf<br />
dem Stack zu erzeugen.<br />
void Counter::higher( Counter c ) {<br />
value_ = value_ + c.value_;<br />
}<br />
Zugriffschutz?<br />
oder besser<br />
void Counter::higher( Counter c ) {<br />
higher(c.value_); // Wiederverwendeter Code<br />
}<br />
22.04.2013 22
Vorgegebene Parameterwerte und variable Parameterzahl /113/<br />
FB Informatik<br />
Prof. Dr. R.Nitsch<br />
Beispiel 1<br />
class Counter {<br />
int value;<br />
Counter( int init = 0 );<br />
…<br />
optionaler Parameter mit default-Wert<br />
}<br />
Konsequenz: Dieser Konstruktor<br />
• kann mit 0 oder 1 Parameter aufgerufen werden!<br />
• ersetzt Counter() und Counter(int)<br />
• ermöglicht schmalere Schnittstelle<br />
int main() {<br />
Counter c1(10);<br />
Counter c2;<br />
…<br />
}<br />
Aktueller Parameter (=10) wird benutzt<br />
Default-Wert (=0) wird benutzt<br />
//Implementation<br />
Counter::Counter( int init )<br />
{ value_ = init; }<br />
Achtung: hier (bei Implementierung) ist kein opt. Parameter erlaubt!<br />
22.04.2013 23
Überladene Methoden/Funktionen mit vorgegebenen Parametern<br />
FB Informatik<br />
Prof. Dr. R.Nitsch<br />
Beispiel 2<br />
enum Color {red, yellow, green};<br />
class Circle {<br />
int x, y;<br />
float radius;<br />
Color c;<br />
…<br />
public:<br />
Circle();<br />
//Standard-Konstruktor<br />
Circle(int xn, int yn, float radius = 1.0f, Color f = red);<br />
Circle(int xn, int yn, Color = red, float radius = 2.0f);<br />
};<br />
// 2. Konstruktor<br />
// 3. Konstruktor<br />
//Anwendung<br />
Circle myCircle(3, 7, 2.0f, green);<br />
Circle c1(4, 26, 3.7f);<br />
Circle c2(4, 17, yellow);<br />
Circle c3;<br />
Circle c4(5);<br />
Circle c5(10,10);<br />
// 2. Konstruktor<br />
// 2. Konstruktor mit Farbe red<br />
// 3. Konstruktor mit radius= 2.0f<br />
//Standard-Konstruktor<br />
// Fehler: kein passender Konstruktor vorhanden<br />
// 2. und 3. Konstruktor würden passen.<br />
Nicht entscheidbar, deshalb Fehler!<br />
22.04.2013 24
Methoden verwenden (andere) Methoden und Attribute<br />
FB Informatik<br />
Prof. Dr. R.Nitsch<br />
Methode ruft Methode derselben Klasse auf<br />
‣Ohne Objektname<br />
‣Mit Objektname<br />
Bezugsbereich ist dasselbe Objekt<br />
Bezugsbereich ist das andere Objekt (z.B. als<br />
Parameter übergeben; kein Zugriffschutz)<br />
Methode ruft Methode einer anderen Klasse auf<br />
‣Mit Objektname<br />
‣Ohne Objektname<br />
Bezugsbereich ist das Objekt der anderen Klasse<br />
(Zugriffschutz bei privaten Methoden und<br />
Attributen!)<br />
geht nur in bestimmten Fällen (Statische Methoden;<br />
kommt später)<br />
22.04.2013 25
dasselbe<br />
Objekt (A1)<br />
anderes Objekt derselben<br />
Klasse (ObjA)<br />
Beispiele<br />
void main(void)<br />
{<br />
KlasseA a1,a2;<br />
KlasseB b1,b2;<br />
a1.publicMethode1vonA(a2, b1)<br />
}<br />
// Datei: KlasseA.cpp<br />
void KlasseA::publicMethode1vonA<br />
( KlasseA objA, KlasseB objB )<br />
{ ...<br />
// ohne Objektname<br />
publicMethode2vonA();<br />
privateMethode2vonA();<br />
publicAttributVonA = ...;<br />
privatesAttributVonA= ...;<br />
// mit Objektname der gl. Klasse<br />
objA.publicMethode2vonA();<br />
objA.privateMethode2vonA();<br />
objA.publicMethode1vonB();<br />
objA.publicAttributVonA = ...;<br />
objA.privatesAttributVonA= ...;<br />
// Anwendung<br />
Objekt a1<br />
KlasseA<br />
Objekt a2<br />
Objekt b1<br />
KlasseB<br />
FB Informatik<br />
Prof. Dr. R.Nitsch<br />
Objekt b2<br />
// <strong>Objekte</strong> a1 und a2 werden erzeugt<br />
// <strong>Objekte</strong> b1 und b2 werden erzeugt<br />
// publicMethode1vonA wird aufgerufen für Objekt a1 und<br />
// Parameter a2 und b1 werden übergeben.<br />
// Definition von publicMethode1vonA<br />
// verarbeitet Daten des (aufrufenden) Objekts a1<br />
// obwohl private ok, weil gleiche Klasse<br />
// Zugriff auf public-Attrib. des (aufrufenden) Obj. a1<br />
// obwohl private ok, weil gleiche Klasse<br />
// verarbeitet Daten des übergebenen objA derselben Klasse<br />
// auch ok, weil gleiche Klasse (kein Zugriffsschutz)<br />
// nicht ok, weil verschiedene <strong>Klassen</strong><br />
// ok, weil public und gleiche Klasse<br />
// auch ok, weil gleiche Klasse (kein Zugriffsschutz)<br />
// Fortsetzung auf nächster Seite<br />
22.04.2013 26
Beispiele<br />
Objekt a1<br />
KlasseA<br />
Objekt a2<br />
Objekt b1<br />
KlasseB<br />
FB Informatik<br />
Prof. Dr. R.Nitsch<br />
Objekt b2<br />
Objekt einer anderen<br />
Klasse (objB)<br />
objB.publicMethode1vonB();<br />
objB.privateMethode1vonB();<br />
objB.publicAttributVonB = ...;<br />
objB.privateAttributVonB= ...;<br />
}<br />
// verarbeitet Daten des objB einer anderen Klasse<br />
// private! Geht nicht (Zugriff von "außen" auf geschützte<br />
// Elemente der anderen Klasse)<br />
// ok, weil public und gleiche Klasse<br />
// private! Geht nicht (Zugriff von "außen" auf geschützte<br />
// Elemente der anderen Klasse)<br />
22.04.2013 Statische Datenelemente 27
Membervariable oder lokale Variable? – Beispiel class Fraction<br />
FB Informatik<br />
Prof. Dr. R.Nitsch<br />
class Fraction<br />
{<br />
private:<br />
int z_,n_;<br />
Fraction result;<br />
// ...<br />
};<br />
// Falsch: nur von lokaler temporärer Bedeutung in add(Fraction b)<br />
Fraction Fraction::multiply(Fraction b)<br />
{<br />
Fraction result;<br />
result.z_ = … ;<br />
result.n_ = … ;<br />
return result;<br />
}<br />
Merke: Membervariable sollen nicht nur von lokaler und/oder temporärer<br />
Bedeutung sein<br />
Dies ist eine Ausprägung des Problemlösungsprinzips<br />
KISS (Keep It Small and Simple)<br />
22.04.2013 28
Konzept der friend-Funktionen<br />
FB Informatik<br />
Prof. Dr. R.Nitsch<br />
Die globale Funktion Fraction get_Fraction(string prompt) ist eng mit der<br />
Klasse Fraction verbunden, gehört aber nicht zu ihrem Namensbereich. Deshalb<br />
schützt die Klasse auch ihre privaten Attribute vor dem Zugriff dieser Funktion.<br />
Eine erfolgreiche Beziehung zwischen einem Subunternehmer und seinem<br />
Generalunternehmer ist auf enge, direkte Zusammenarbeit angewiesen. So wird i.A.<br />
der Subunternehmer direkten Zugriff auf bestimmte Informationen des<br />
Gerneralunternehmers haben.<br />
Das gleiche Erfolgsrezept wird im Bereich der <strong>Klassen</strong> mit dem friend-Konzept<br />
verwirklicht.<br />
Durch eine friend-Deklaration kann der Zugriffschutz selektiv für bestimmte<br />
Funktionen (oder <strong>Klassen</strong>) aufgehoben und der direkte Zugriff auf alle Attribute<br />
gewährt werden.<br />
Beispiel:<br />
class Fraction {<br />
private:<br />
int z_, n_;<br />
public:<br />
friend Fraction get_Fraction(string prompt);<br />
friend class TestFraction;<br />
Fraction get_Fraction(string prompt){<br />
Fraction frac;<br />
cout frac.z_>>frac.n_;<br />
// …<br />
}<br />
Zugriff von "aussen"<br />
möglich durch friend-Eigenschaft!<br />
gewährt der bezeichneten Funktion direkten<br />
Zugriff auf alle privaten Attribute (hier: z_, n_).<br />
…<br />
};<br />
gewährt der Klasse TestFraction, d.h.allen Memberfunktionen dieser<br />
Klasse direkten Zugriff auf alle privaten Attribute (hier: z_, n_).<br />
22.04.2013 <strong>Klassen</strong>-Schnittstelle 29