Einführung in das Programmieren mit C++ - Markus Uhlmann

Werbung
Einleitung
Überladen binärer arithmetischer Operatoren
Weitere Operatoren
Informationsverarbeitung
Einführung in das Programmieren mit C++
Markus Uhlmann
Institut für Hydromechanik
Karlsruher Institut für Technologie
www.ifh.kit.edu
WS 2011/2012
Vorlesung 12
(Download Quelldateien)
1/24
Einleitung
Überladen binärer arithmetischer Operatoren
Weitere Operatoren
12. VORLESUNG
Überladen von Operatoren
Advice: Define operators primarily to mimic conventional usage.
– B. Stroustrup
2/24
Einleitung
Überladen binärer arithmetischer Operatoren
Weitere Operatoren
Fragen, die in dieser Vorlesung diskutiert werden
I
Wie können Operationen zwischen Objekten durch
“natürliche” Operatorsymbole ausgedrückt werden?
I
Welche Möglichkeiten und Beschränkungen bestehen dabei?
3/24
Einleitung
Überladen binärer arithmetischer Operatoren
Weitere Operatoren
Wieso Überladen von Operatoren?
Beispiel: Arbeiten mit Vektoren
I
Addition von Vektoren: Addieren jedes Elementes
int ort[3], verschiebung[3], resultat[3];
for (int i=0; i<3; i++)
resultat[i]=ort[i]+verschiebung[i];//Addition per Element
I
implementiert durch eine Klasse “vektor”:
vektor ort, verschiebung, resultat;
resultat=ort.add(verschiebung); //Addition von Objekten
I
wäre Folgendes nicht praktisch?
resultat=ort+verschiebung; //Addition von Objekten
⇒ Operator “+” überladen durch Additionsfunktion für Klasse
“vektor”
4/24
Einleitung
Überladen binärer arithmetischer Operatoren
Weitere Operatoren
Überladen von Operatoren: wie funktioniert es?
resultat = ort + verschiebung; //Addition von Objekten
typische Notation für Addition
→ verbirgt den Mechanismus (Details), betont das Essentielle
I
I
Syntax für Operatorfunktionen:
<rueckgabeTyp> operator <op> (<parameterListe>)
I
Compiler ersetzt
I
durch
resultat=ort.operator+(verschiebung);
<op> beinhaltet i.d.R. Sonderzeichen (hier erlaubt)
resultat=ort+verschiebung;
5/24
Einleitung
Überladen binärer arithmetischer Operatoren
Weitere Operatoren
Operator +
Beschränkungen
Operatoren -, *
Einführung in überladene Operatoren an einem Beispiel
Eine Klasse zur Behandlung von Zeitdaten
Zeitangabe bestehend aus Stunden, Minuten
I Wertebereich der Minuten: [0, 59]
→ 2 Ganzzahlen
I Funktionen: Anzeigen, Summieren, Initialisieren, . . .
I
12
13
14
15
16
17
18
19
20
21
22
23
class Time{
private:
int hours;
int minutes;
public:
Time();
Time(int h, int m=0);
void AddMin(int m);
void AddHr(int h);
void Reset(int h=0, int m=0);
Time Sum(const Time t) const;
void Show() const;
Version: ohne überladene Ops.
27
28
29
44
45
Time vorbereitung(1,30);
Time implementierung(1,10);
Time fehlersuche(0,40);
gesamt=vorbereitung.Sum(implementierung);
gesamt=gesamt.Sum(fehlersuche);
(Quelltext 12.1)
6/24
Einleitung
Überladen binärer arithmetischer Operatoren
Weitere Operatoren
Operator +
Beschränkungen
Operatoren -, *
Version mit überladenem Additionsoperator
Ersetzen der Funktion “Sum” durch Operator “+”
⇒ ermöglicht Operator- oder Funktionsschreibweise
I
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Time{
private:
int hours;
int minutes;
public:
Time();
Time(int h, int m=0);
void AddMin(int m);
void AddHr(int h);
void Reset(int h=0, int m=0);
Time operator+(const Time t)
const;
void Show() const;
};
Version: mit überladenem “+”
27
28
29
30
43
44
45
46
47
Time
Time
Time
Time
vorbereitung(1,30);
implementierung(1,10);
fehlersuche(0,40);
gesamt;
gesamt=vorbereitung+implementierung;
gesamt=gesamt+fehlersuche;
/* funktioniert auch:
gesamt=gesamt.operator+(fehlersuche);
*/
(Quelltext 12.2)
7/24
Einleitung
Überladen binärer arithmetischer Operatoren
Weitere Operatoren
Operator +
Beschränkungen
Operatoren -, *
Regeln des Überladens von Operatoren (i)
Regel 1: nur existierende Operatorsymbole verwenden
es ist nicht möglich neue Operatorsymbole zu definieren
B Bsp: Operator “**” zur Potenzierung (nicht möglich)
I
Regel 2: manche Operatoren können nicht überladen werden
Operatorsymbole, die nicht zu überladen sind:
B “sizeof”, “.”, “::”, “?” (und weitere)
I die meisten Operatorsymbole sind überladbar (sh. Tabelle)
I
8/24
Einleitung
Überladen binärer arithmetischer Operatoren
Weitere Operatoren
Operator +
Beschränkungen
Operatoren -, *
Regeln des Überladens von Operatoren (ii)
Regel 3: mind. ein Operand muss benutzerdefiniert sein
Überladen von Operatoren soll neuen Datentypen dienen
I soll verhindern, Standardoperationen neu zu definieren
B Bsp: Redefinition von “-” für zwei Ganzzahlen nicht möglich
I
Regel 4: Eigenschaften des Operators bleiben unverändert
Überladen kann nicht die Priorität des Operators ändern
ebenso bleibt Anzahl der Operanden erhalten
B Bsp:
I
I
int x=5;
Time training;
% x;
//illegal fuer Restwertoperator
% training; //illegal fuer ueberladenen Op.
9/24
Einleitung
Überladen binärer arithmetischer Operatoren
Weitere Operatoren
Operator +
Beschränkungen
Operatoren -, *
Regeln des Überladens von Operatoren (iii)
Regel 5: einige Operatoren müssen Elementfunktionen sein
die meisten Operatoren können entweder als
Elementfunktionen oder nicht-Elementfunktionen
implementiert werden
B Ausnahmen sind: “=”, “()”, “[]”, “->”
⇒ nur als Elementfunktionen zu redefinieren
I
Empfehlung: Überladen sinnverwandt mit Originaloperator
Operatorsymbol soll Sinn der Operation suggerieren
I bei Nichtbeachtung: unverständlicher Code
B Bsp: Überladen von “*” durch Vektoraddition (nein!)
I
10/24
Einleitung
Überladen binärer arithmetischer Operatoren
Weitere Operatoren
Operator +
Beschränkungen
Operatoren -, *
Zeitklasse mit weiteren Operatoren (Version 1)
I
I
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Funktion für Subtraktion zweier Zeitspannen:
Multiplikation einer Zeitspanne mit Faktor:
class Time{
private:
int hours;
int minutes;
public:
Time();
Time(int h, int m=0);
Time operator+(const Time t)
const;
Time operator-(const Time t)
const;
Time operator*(const float mult)
const;
void Show() const;
“-”
“*”
Version: mit +, -, *
27
28
29
30
42
43
44
int main(){
Time planen(18,30);
Time herstellen(60,0);
Time gesamt,diff,korrigiert;
gesamt=planen+herstellen;
diff=herstellen-planen;
korrigiert=gesamt*1.25;
(Quelltext 12.3)
11/24
Einleitung
Überladen binärer arithmetischer Operatoren
Weitere Operatoren
Operator +
Beschränkungen
Operatoren -, *
Zeitklasse mit weiteren Operatoren: Problem
Multiplikationsoperator erlaubt keine Vertauschung
I
Multiplikation “gesamt*1.25” möglich (s.o.)
I
mathematisch äquivalentes “1.25*gesamt” nicht möglich!
I
wieso nicht?
Elementfunktion: erster Operand ist aufrufendes Objekt
→ aber hier “1.25” kein Objekt!
I
Lösung:
Implementierung des Operators als nicht-Elementfunktion
⇒ Funktion benötigt folgende Signatur (Prototyp):
Time operator*(double mult, Time t)
⇒ Funktion benötigt Zugriffsrechte auf Elementvariablen
→ Deklaration als friend in Klasse Time
12/24
Einleitung
Überladen binärer arithmetischer Operatoren
Weitere Operatoren
Operator +
Beschränkungen
Operatoren -, *
Zeitklasse mit weiteren Operatoren (Version 2)
I
12
13
14
15
16
17
18
19
20
21
22
23
24
25
nicht-Elementfunktion wird Teil der Schnittstelle der Klasse
class Time{
private:
int hours;
int minutes;
public:
Time operator+(const Time t)
const;
Time operator-(const Time t)
const;
Time operator*(const float mult)
const;
friend Time operator*(
const float mult,
const Time t);
Version: mit friend
31
32
33
34
46
47
48
49
int main(){
Time planen(18,30);
Time herstellen(60,0);
Time gesamt,diff,korrigiert;
//Elementfunktion:
korrigiert=gesamt*1.25;
//nicht-Elementfunktion:
korrigiert=1.25*gesamt;
(Quelltext 12.4)
13/24
Einleitung
Überladen binärer arithmetischer Operatoren
Weitere Operatoren
Operator +
Beschränkungen
Operatoren -, *
Zeitklasse mit weiteren Operatoren (Version 3)
I
I
12
13
14
15
16
17
18
19
20
21
22
23
24
25
friend Status kann vermieden werden:
nicht-Elementfunktion kehrt lediglich Reihenfolge um
aber: Funktion taucht nicht in Deklaration von Time auf
class Time{
private:
105
int hours;
106
int minutes;
107
public:
108
Time operator+(const Time t)
109
const;
110
Time operator-(const Time t)
111
const;
112
Time operator*(const float mult)
113
const;
114
//keine ’friend’ Deklaration
115
void Show() const;
Time();
Version: ohne friend
Time operator*(
const float mult,
const Time t){
//ruft nur oeffentliche
// Elementfunktion mit
// umgekehrter Reihenfolge
// auf
//-> benoetigt keinen
// ’friend’ Status
return t*mult;
};
(Quelltext 12.5)
14/24
Einleitung
Überladen binärer arithmetischer Operatoren
Weitere Operatoren
Operator +
Beschränkungen
Operatoren -, *
Bemerkungen zu nicht-Elementfunktionen
I
nicht-Elementfunktionen, welche die Funktionalität einer
Klasse erweitern ≡ Hilfsfunktionen
I
Hilfsfunktionen sollten zusammen mit eigentlicher Klasse
deklariert und definiert werden
⇒ Quelltext in gleicher Datei wie Klasse anordnen
Elementfunktion oder nicht-Elementfunktion?
I
manche Operatoren erlauben nur Elementfunktion (s.o.)
I
sonst: beide Optionen meist äquivalent
15/24
Einleitung
Überladen binärer arithmetischer Operatoren
Weitere Operatoren
Operator <<
Beispiel: komplexe Zahlen
Überladen des Operators “<<” zur Ausgabe von Time
Bildschirmausgabe durch Objekt cout (Typ ostream)
I
Operator “<<” ist bereits überladen für diverse Basistypen
I
wir wünschen uns Folgendes für die Klasse Time:
Time film(1,30);
cout << film; //gibt Laenge des Films aus
⇒ Implementierung als nicht-Elementfunktion
(eigenes Objekt muss dann nicht erster Operand sein)
16/24
Einleitung
Überladen binärer arithmetischer Operatoren
Weitere Operatoren
Operator <<
Beispiel: komplexe Zahlen
Operator “<<” für die Klasse Time (Version 1)
I
I
analog zu Operator “*” in Programm 12.4
Problem: diese Version erlaubt keine Verkettung
Version: void
19
20
21
22
23
24
25
26
27
28
29
class Time{
private:
int hours;
int minutes;
public:
Time();
Time(int h, int m=0);
friend void operator<<(
ostream & os,
const Time & t);
};
31
32
33
34
54
55
56
57
58
int main(){
Time halbzeit1(0,45);
cout << "Halbzeit1: ";
cout << halbzeit1;
void operator<<(ostream & os,
const Time & t) {
os << t.hours << " Stunden, "
<< t.minutes << " Minuten";
}
(Quelltext 12.6)
17/24
Einleitung
Überladen binärer arithmetischer Operatoren
Weitere Operatoren
Operator <<
Beispiel: komplexe Zahlen
Operator “<<” für die Klasse Time (Version 2)
Verkettung von Ausgabeoperationen: cout<<zeit1<<zeit2
⇒ jede einzelne Operation muss Objekttyp “ostream” liefern
I
14
15
16
17
18
19
20
21
22
23
24
class Time{
private:
int hours;
int minutes;
public:
Time();
Time(int h, int m=0);
friend ostream & operator<<(
ostream & os,
const Time & t);
};
Version: ostream &
31
32
33
34
35
36
37
38
/* Verkettung funktioniert: */
cout << "Halbzeit1: "
<< halbzeit1
<< "; Halbzeit2: "
<< halbzeit2
<< "; Nachspiel: "
<< nachspiel
<< endl;
(Quelltext 12.7)
18/24
Einleitung
Überladen binärer arithmetischer Operatoren
Weitere Operatoren
Operator <<
Beispiel: komplexe Zahlen
Beispiel: Klasse für komplexe Zahlen
Komplexe Zahlen
I
komplexe Zahlen besitzen
√ Real- und Imaginärteil
c = cr + I ci mit: I = −1 und reellen cr , ci
I
Konsequenzen für arithmetische Operationen
→ Überladen von Operatoren bietet sich an
B es existiert eine Klasse complex in Standardbibliothek
→ dieser Entwurf dient nur zu Übungszwecken
19/24
Einleitung
Überladen binärer arithmetischer Operatoren
Weitere Operatoren
Operator <<
Beispiel: komplexe Zahlen
Klasse complex
Deklaration
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
class complex{
private:
//Elementdaten
double re; //Realteil
double im; //Imaginaerteil
//-> c=c.re+c.im*I
//[’I’ steht fuer wurzel(-1)]
public:
//Konstruktor:
complex(double r=0, double i=0) :
re(r), im(i) { }
//Zugriffsfunktionen:
double real() const {return re;}
double imag() const {return im;}
//Zusammengesetzte binaere Operatoren:
complex operator+=(complex c);
complex operator+=(double d);
complex operator*=(complex c);
complex operator*=(double d);
//fehlen: ’-=’,’/=’
};
(Quelltext 12.8)
20/24
Einleitung
Überladen binärer arithmetischer Operatoren
Weitere Operatoren
Operator <<
Beispiel: komplexe Zahlen
Klasse complex (ii)
Implementierung
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
complex complex::operator+=(complex c){
re += c.re;
im += c.im;
return *this; //’this’ pointer zeigt auf das
//Objekt selber
}
complex complex::operator+=(double d){
re += d;
return *this;
}
complex complex::operator*=(complex c){
//Vorschrift zur Multiplikation
// zweier komplexer Zahlen:
//a*b=(ar+I*ai)*(br+I*bi)
//
=(ar*br-ai*bi)+I*(ai*br+bi*ar)
double r = re*c.real()-im*c.imag();
double i = im*c.imag()+re*c.real();
re = r;
im = i;
return *this; //’this’ pointer zeigt auf das
//Objekt selber
}
complex complex::operator*=(double d){
re *= d;
im *= d;
return *this;
}
21/24
Einleitung
Überladen binärer arithmetischer Operatoren
Weitere Operatoren
Operator <<
Beispiel: komplexe Zahlen
Klasse complex (iii)
Hilfsfunktionen
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
//1. binaere Operatoren
complex operator+(complex a, complex b){
complex r = a;
return r += b;//Aufruf: complex::operator+=(complex)
}
complex operator+(complex a, double b){
complex r = a;
return r += b;//Aufruf: complex::operator+=(double)
}
complex operator+(double a, complex b){
complex r = b;
return r += a;//Aufruf: complex::operator+=(double)
}
complex operator*(complex a, complex b){
complex r = a;
return r *= b;//Aufruf: complex::operator*=(complex)
}
complex operator*(complex a, double b){
complex r = a;
return r *= b;//Aufruf: complex::operator*=(double)
}
complex operator*(double a, complex b){
complex r = b;
return r *= a;//Aufruf: complex::operator*=(double)
}
//fehlen: ’-’,’/’
22/24
Einleitung
Überladen binärer arithmetischer Operatoren
Weitere Operatoren
Operator <<
Beispiel: komplexe Zahlen
Klasse complex (iv)
Hilfsfunktionen – 2
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
//2. unaere Operatoren
complex operator+(complex a){
return a;
}
/* complex operator-(complex a){
return a*(double(-1));//Aufruf: complex::operator*=(double)
} */
//3. Vergleichsoperatoren
bool operator==(complex a, complex b){
return a.real() == b.real() &&
a.imag() == b.imag() ;
}
//fehlt: ’!=’
//4. Ein/Ausgabeoperatoren
ostream & operator<<(ostream & os, complex c){
os << c.real() << "+I*(" << c.imag() <<")";
return os;
}
//fehlt: ’>>’
//5. diverse mathematische Funktionen
complex conj(complex c){
//konjugiert komplexe Zahl
complex r=complex(c.real(),c.imag()*(-1));
return r;
}
23/24
Einleitung
Überladen binärer arithmetischer Operatoren
Weitere Operatoren
Operator <<
Beispiel: komplexe Zahlen
Klasse complex (v)
Testprogramm
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
int main(){
//einige moegliche Operationen mit Typ ’complex’
complex a = complex(1,2);
cout << "a = " << a << endl;
complex b = 3;
cout << "b = " << b << endl;
complex c = a+2.3;
cout << "c = a+2.3 = " << c << endl;
complex d = 2+b;
cout << "d = 2+b = " << d << endl;
complex e = a*c;
cout << "e = a*c = " << e << endl;
return 0;
}
24/24
Anhang
Zusammenfassung
Literatur
Mehr
Zusammenfassung
I
Überladen von Operatoren erlaubt intuitiven Syntax bei
Operationen zwischen Objekten
B sollte wohldosiert eingesetzt werden
I
Elementfunktion: erster Operand ist aufrufendes Objekt
I
falls dies nicht erwünscht: nicht-Elementfunktion
I
überladene Operatoren behalten ihre Eigenschaften:
Anzahl der Operanden, Priorität, Assoziativität
1/5
Anhang
Zusammenfassung
Literatur
Mehr
Anhang
2/5
Anhang
Zusammenfassung
Literatur
Mehr
Weiterführende Literatur
I
S. Prata, “C++ Primer Plus”, Sams, 2005
I
S. Oalline, “Practical C++ Programming”, O’Reilly, 2003
I
J. Liberty and B. Jones, “Teach yourself C++ in 21 days”,
Sams, 2005
I
R. Lischner, “C++ in a Nutshell”, O’Reilly, 2003
I
Handbücher erhältlich am Rechenzentrum: (Weblink)
I
I
RRZN, “Die Programmiersprache C”, 17. Auflage, 2008
RRZN, “C++ für C Programmierer”, 13. Auflage, 2005
I
Online Dokumentation zum C++ Standard (Weblink)
I
(freie) Microsoft Software für Studenten am KIT: (Weblink)
3/5
Anhang
Zusammenfassung
Literatur
Mehr
Bedingungsoperator “?”
Der einzige “ternäre” Operator (mit 3 Operanden) in C++
I
Syntax:
<bedingung> ? <Anweisung1> : <Anweisung2>
I
I
falls <bedingung> wahr: führt <Anweisung1> aus,
sonst: führt <Anweisung2> aus
Abkürzung für äquivalentes “if...else”
int main (){//Bsp: Operator ?
int a=2,b=7,c;
c = (a>b) ? a : b;
cout << c;
return 0;}
int main (){//Bsp: if...else
int a=2,b=7,c;
if (a>b)
c=a;
else
c=b;
cout << c;
return 0;}
4/5
Anhang
Zusammenfassung
Literatur
Mehr
Operatorsymbole, die überladen werden können
+
&
>
^=
<<=
||
()
|
+=
&=
==
++
[]
*
~=
-=
|=
!=
-new
/
!
*=
<<
<=
,
delete
%
=
/=
>>
>=
->*
new []
^
<
%=
>>=
&&
->
delete []
5/5
Herunterladen