Hydroinformatik I ”C++ und Visual C++”
Version 4.01 - 12. April 2012
Hydroinformatik I
”C++ und Visual C++”
Olaf Kolditz & Bastian Kolditz
TU Dresden / UFZ Leipzig
Angewandte Umweltsystemanalyse
Umweltinformatik
SoSe 2012
c
OGS Teaching 2012
2
Vorlesungskonzept
Ein wesentlicher Bestandteil der Hydroinformatik ist die Informationsverarbeitung. Typische Hydrodaten sind z.B: digitale Gel¨andemodelle (DGM), Niederschlagsmessungen, Wasserpegel, Bodentemperaturen, Bodenkarten (Bodentypen), geologische Schnitte u.v.a. (s. Abb. 1 und 2)
Abbildung 1: Informationsverarbeitung in der Hydrologie - Datentypen
Eine grundlegende Methodik f¨
ur die Informationsverarbeitung ist die wissenschaftliche Programmierung. Daher besch¨aftigen wir uns im ersten Semester
der Veranstaltung ’Hydroinformatik’ mit der objekt-orientierten Programmierung in C++.
Es gibt zwei M¨
oglichkeiten eine Programmiersprache zu erlernen: mehr theoretisch oder mehr praktisch. Wir beschreiten den zweiten Weg. Das heißt anhand
von dem, was wir f¨
ur das Programmieren ben¨otigen, erarbeiten wir uns die
Theorie. Unser Motto ist ’Learning by doing’.
3
.
Abbildung 2: Informationsverarbeitung in der Hydrologie - Beispiel aus der Hydrogeologie
Organisatorisches
Die Pr¨
ufung ’Hydroinformatik I’ (erstes Semester) ist eine Klausur. Die Pr¨
ufung
’Hydroinformatik II’ (zweites Semester) besteht aus zwei Teilen, einer Klausur
und einer Programmier-Hausarbeit. Bei den Klausuren geht es um die Beantwortung von Verst¨
andnisfragen (siehe Testfragen zu jeder Vorlesung).
Sprache: normalerweise in Deutsch. Da die Syntax von Computersprachen (wie
C++) immer in Englisch ist, w¨
urde ich auch mal eine Vorlesung in Englisch
anbieten.
Konsultationen: immer nach der Vorlesung (Freitag ab 11 Uhr).
Kontakt: jederzeit by e-mail ([email protected]), in dringenden F¨allen auch
per Handy (0151 52739034), ich empfehle auch eine mailing Liste der Studenten
anzulegen, wenn alle damit einverstanden sind.
Vorlesungsunterlagen: lege ich erstmal auf meinem UFZ Server ab
(http://www.ufz.de/index.php?de=11877).
4
Es gibt viele und sehr gute C++ B¨
ucher. Bei Amazon finden sie locker u
¨ ber
50 C++ B¨
ucher (Abb. 3). Sehr gut finde das Buch von Prinz & Prinz ”C++
- Lernen und professionell anwenden”, da es eine gute Kombination aus Theorie und Programm-Beispielen ist. Zu diesem Lehrbuch gibt es auch ein extra
¨
Ubungsbuch.
Unsere Vorlesung lehnt sich an dieses Buch an.
Abbildung 3: C++ Literatur
Das heisst, etwas anders wird unsere Vorgehensweise sein. Im ersten Semester
wollen wir zielgerichtet die C++ Grundlagen anhand der Entwicklung einer
einfachen ’Datenbank’-Anwendung erlernen - learning-by-doing - und die Daten
schließlich in einer graphischen Benutzerschnittstelle (GUI) sichtbar machen.
Somit besch¨
aftigen wir uns auch zielgerichtet mit den Grundlagen von Visual
C++.
Das Vorlesungskonzept:
• Zielgerichtetes Erlernen der C++ Grundlagen,
• Entwicklung einer ’Datenbank’-Anwendung,
• Umsetzung in eine graphische Benutzerschnittstelle (Visual C++, C++
GUI), siehe Abb. 4.
5
.
Abbildung 4: Vorlesungs-Konzept
Die Implementierung des Dialogs in Abb. 4 ist das erste greifbare Ziel der Veranstaltung Hydroinformatik I. In dieser GUI-Anwendung k¨onnen sie (fast) alles,
was wir lernen werden, wiederfinden: Datentypen, Ein- und Ausgabe mit verschiedene Ger¨
aten (Tastatur, Bildschirm, Dateien), Klassen, Vererbung, Container (Listen, Vektoren) und graphische Programmierung unter Windows. Es
lohnt sich also dranzubleiben ...
Part I
C ++ Basics
Kapitel 1
Einfu
¨ hrung
7
¨
KAPITEL 1 EINFUHRUNG
8
1.1
Historisches
Die Programmiersprache C++ wurde von dem d¨anischen Informatiker Bjarne Stroustrup in den Bell Labs des nordamerikanischen Telekommunikationskonzerns AT&T (American Telephone & Telegraph Corporation) ab 1979/80
entwickelt. C++ stellt eine Weiterentwicklung der ebenfalls von AT&T entwickelten, Programmiersprache C dar. Die Programmiersprache C wurde als
Grundlage f¨
ur C++ aufgrund seiner effizienten Codeverarbeitung und einfachen
¨
Ubertragbarkeit
auf anderen Plattformen verwendet. C wurde in C++ nach dem
Vorbild der Programmiersprache Simula-67 (1967), der ersten objektorientierten
Programmiersprache, im Wesentlichen um ein Klassenkonzept, d.h. die Abbildung von Objekten in verschiedenen Klassen mit unterschiedlichen Attributen,
erweitert. Daher wurde C++ zun¨achst unter dem Namen ’C mit Klassen’ (C
with classes) entwickelt. Der Name C++ wurde 1983 von Rick Mascitti erstmals angewandt. Dabei ist das ++ eine Andeutung an den Inkrement-Operator
(Inkrement: Erh¨
ohung einer Variable um 1), der die Verbesserungen gegen¨
uber
dem Vorg¨
anger C zum Ausdruck bringen soll. Im Jahr 1985 erschien die erste
Version von C++, die eine wichtige Grundlage f¨
ur die weitere Entwicklung und
Standardisierung von C++ darstellte, da die Sprache zu dieser Zeit noch nicht
akzeptiert war. Im Jahre 1989 erschien die erweiterte Version 2.0 von C++.
In den 90er Jahren begann nun der Standardisierungs- und Vereinheitlichungsprozess von C++, der eingeleitet wurde durch das Buch ’The Annotated C++
Reference Manual’ (1990) von Margaret Ellis und Bjarne Stroustrup. Die genormte Fassung von C++ erschien 1998 (ISO/IEC 14882:1998), die 2003 mit
einer neuen Version (ISO/IEC 14882:2003) nochmals nachgebessert wurde.
Abbildung 1.1: Bjarne Stroustrup (http://www.research.att.com/bs/)
1.2 PARADIGMEN
1.2
9
Paradigmen
Programmier-Paradigmen sind sogenannte Leitlinien / Konzepte f¨
ur die Gestaltung von Programmen, diese k¨onnen durch entsprechende Sprachmittel unterst¨
utzt werden. Allerdings bedeutet die Benutzung einer objekt-orientierten
Sprache nicht automatisch ein objekt-orientiertes Programm (OOP).
• Prozedurales Programmieren: Welche Prozeduren ben¨otigen Sie f¨
ur Ihr
Programm ? Verwenden Sie die optimalen Algorithmen.
• Modulares Programmieren: Welche Module ben¨otigen Sie f¨
ur Ihr Programm ? Strukturieren Sie Ihr Programm entsprechend modular. Die Daten sollten in den Modulen gekapselt sein.
• Objekt-orientiertes Programmieren: Welche Klassen ben¨otigen Sie f¨
ur Ihr
¨
Programm ? Uberlegen
Sie, welche Gemeinsamkeiten die Klassen haben,
benutzen Sie das Konzept der Vererbung.
• Datenabstraktion: Welche Datentypen ben¨otigen Sie f¨
ur Ihr Programm ?
Erstellen Sie f¨
ur jeden benutzerdefinierten Typen m¨oglichst viele Operationen.
10
¨
KAPITEL 1 EINFUHRUNG
.
Abbildung 1.2: Objekt-orientiertes Programmieren - OOP
Die Abb. 1.2 soll das Konzept des Objekt-Orientierten Programmierens (OOP)
mal aus einer anderen Sichtweise erl¨autern. Normalerweise bedeutet die Programmentwicklung (prozedural und modular) eine stetige Erweiterung des Codes (Abb. oben). Irgendwann ist das Programm dann so un¨
ubersichtlich geworden, dass eigentlich niemand mehr durchblickt. Die grundlegenden Idee von
OOP dagegen sind, dass, erstens Objekte (logische Einheiten des Programms)
streng gekapselt sind (sich also nicht gegenseitig beeinflussen) und, zweitens,
dass es ganz schmale Schnittstellen zwischen diesen Objekten gibt (z.B. nur
u
urlich wachsen auch
¨ ber eine Adresse (sogenannte pointer)) (Abb. unten). Nat¨
diese Objekte weiter und stoßen irgendwann an Grenzen ...
Ein Beispiel aus der Praxis unserer eigenen Programmentwicklung OpenGeoSys. Die Abb. 1.3 zeigt das objekt-orientierte Konzept der Kernels von OpenGeoSys zur L¨
osung von partiellen Differentialgleichungen. Letztlich f¨
uhren alle
numerischen Methoden zur L¨osung von linearen Gleichungssystemen Ax = b.
Daher haben wir ein Objekt konstruiert (PCS von ProCesS), das die Aufgabe
u
ur die Assemblierung und L¨osung der Gleichungs¨ bernimmt, alle Bausteine f¨
systeme einzusammeln. Dabei geht es um geometrische (Punkte, Polylinien,
Fl¨
achen, Volumen), topologische (Element-Netze), numerische und physikalische Daten (z.B. Materialeigenschaften, Anfangs- und Randbedingungen). Entscheidend f¨
ur die Machbarkeit eines objekt-orientierten Konzepts ist, dass der
Algorithmus zum Aufstellen und L¨osen der Gleichungssysteme vollkommen
unabh¨
angig von dem spezifischen physikalischen Problem ist. Die Basisklasse
1.3 COMPILER
11
f¨
ur das PCS-Objekt ist CProcess, davon abgeleitet werden die speziellen Klassen f¨
ur die spezifischen Probleme (z.B. Str¨omung, Stoff- und W¨armetransport,
Deformation). Wenn Sie diesen Abschnitt noch mal durchlesen, sollten sie allerdings stutzig werden, da neben dem erwarteten Begriff der Objekt-Orientierung
auf der des Algorithmus auftaucht. Richtig, OpenGeoSys ist kein reines OOP
sondern eine Kombination von objekt-orientierten und prozeduralen Konzepten.
Anyway, der Schritt von C zu C++ (3. zur 4. Version, Abb. 1.3) bedeutete eine
Reduzierung des Quellcodes von 10MB auf 3MB, also um 70% !!!
Abbildung 1.3: Objekt-orientiertes Konzept des Kernels von OpenGeoSys
1.3
Compiler
Bevor wir irgendetwas programmieren k¨onnen, ben¨otigen wir zwei Werkzeuge:
einen Editor und einen Compiler. In der Abb. 1.4 sind die wichtigsten Schritte
der Programmerstellung zu sehen.
In der Computer-Welt (und deshalb auch in der Programmier-Welt) gibt es zwei
verschiedene Philosophien: Microsoft (MS) und ’den Rest’. Um diesem Problem
’auszuweichen’ und fair zu sein, benutzen wir Werkzeuge aus beiden Welten.
Wir beleuchten dieses ’Problem’ sp¨ater noch mal, wenn wir u
¨ ber Open Source
Projekte (z.B. OpenGeoSys, unsere eigene Software-Entwicklung) sprechen. Wir
installieren uns zun¨
achst den GNU Compiler (Abschn. 1.3.1) und sp¨ater den MS
Compiler (Abschn. 1.3.2) f¨
ur das visuelle C++ Programmieren.
¨
KAPITEL 1 EINFUHRUNG
12
Editor
Source file
Header file
Compiler
Object file
Linker
Libraries
Executable
Abbildung 1.4: Quell-Code Kompilation
1.3.1
GNU
Das GNU-Projekt wurde von Richard Stallman mit dem Ziel gegr¨
undet, ein
vollst¨
andig freies Betriebssystem, genannt GNU (”GNU is not Unix”), zu entwickeln. Bekannt geworden ist das Projekt vor allen Dingen auch durch die von
ihm eingef¨
uhrte GNU General Public License (GPL), unter der viele bekannte
Softwareprojekte ver¨
offentlicht werden (Quelle: Wikipedia).
Wenn ihr mehr u
¨ ber das GNU Projekt erfahren wollt, schaut nach unter
http://de.wikipedia.org/wiki/GNU-Projekt
Als Kompromiss benutzen wir cygwin (Abb. 1.5). Dass erm¨oglicht uns, auch
unter Windows mit GNU Software arbeiten zu k¨onnen. Die Linux / Ubuntu
’Freaks’ haben die GNU Software automatisch mit dem Betriebssystem auf ihrem Rechner. Die Anleitung zur Installation finden sie im Anhang, Abschn.
11.3.2.2 (und wird nat¨
urlich in der Vorlesung besprochen)
1.3 COMPILER
13
.
Abbildung 1.5: Ein Kompromiss: cygwin
1.3.2
MS Visual C++
Auch die nicht-MS-Fans m¨
ussen zugeben, das MS Visual C++ Studio ist eine
tolle Entwicklungsumgebung. Die wird uns enorm helfen, wenn wir uns sp¨ater
mit GUI Programmierung besch¨
aftigen. Die Express-Version von VC++ kann
kostenlos direkt bei Microsoft unter
http://www.microsoft.com/germany/express/download/webdownload.aspx heruntergeladen werden.
1.3.3
Qt
Als plattformunabh¨
angiges visuelles C++ empfehle ich Qt (siehe Abschn. 10
und 11.4)
¨
KAPITEL 1 EINFUHRUNG
14
1.4
”Hello World”
Unser allererstes C++ Programm.
1.4.1
Grundlagen
Jedes C/C++ Programm ben¨otigt eine main() Funktion
int main()
{
return 0;
}
Die main() Funktion ist der ’Startpunkt’ eines jeden C/C++ Programms. Die
wichtigsten Bausteine einer Funktion sind:
• Typ (R¨
uckgabewert): int (return 0)
• Name: main
• Argumente: (), man kann die main Funktion auch mit Argumenten aufrufen, z.B. der Name der Eingabe-Datei,
• Funktionsrumpf: ...
Die Struktur der main() Funktion ist in der Abb. 1.6 dargestellt.
function type
function name
function arguments
function start
function end
int main()
{
...
return 0;
}
function block
Abbildung 1.6: Struktur der Funktion main()
1.4 ”HELLO WORLD”
1.4.2
15
Exercise E1
Abbildung 1.7: cygwin aufrufen
Abbildung 1.8: cygwin drive ist /cygwin/home/user, wechseln zum Arbeitsverzeichnis cd c:/myworkdirectory (oder copy und paste)
Abbildung 1.9: slash (/) ist nicht gleich slash (\)
¨
Die einzige C Ubung:
#include <stdio.h>
int main()
{
printf("Hello World");
return 0;
}
Abbildung 1.10: Kommandozeile: gcc main.c, das Ergebnis ist a.exe, Aufruf des
Programms: ./a
Jetzt endlich zu C++ ...
¨
KAPITEL 1 EINFUHRUNG
16
#include <iostream>
using namespace std;
int main()
{
cout << "Hello World" << endl;
return 0;
}
Abbildung 1.11: Kommandozeile: g++ main.cpp, mit ls den Inhalt des Verzeichnisses ansehen, das Ergebnis ist a.exe, Aufruf des Programms: ./a
1.5
Students Forum
Vielen Dank f¨
ur Ihre Fragen zur Vorlesung!
JB Der C compiler funktioniert, der C++ aber nicht: Wahrscheinlich haben
sie nur den C Compiler (GCC) installiert. Die k¨onnen jederzeit cygwin
Komponenten nachinstallieren, siehe Abschn. 11.3.2.2.
¨
DB Ich habe den MS VC++ installiert und kann die Ubungen
nachvollziehen.
Brauche ich den GNU Compiler von cygwin wirklich noch ?: Eigentlich
nicht, mit MS VC++ haben sie einen kompletten Compiler mit allem
drum und dran, dennoch kann ein Ausflug in die Konsolenwelt ja nicht
schaden ... und sie k¨onnen sp¨ater in ihre Bewerbungen schreiben, dass sie
auch unter Linux Programme entwickelt haben.
MF Die aktuelle cygwin Installation sieht anders aus als im Skript beschrieben:
[OK] Im Anhang (Abschn. 11.3.2.2) finden sie eine bessere Beschreibung
der cygwin Installation.
C++ und Mac Hier die Adresse http://developer.apple.com/TOOLS/xcode/
wo sie den MAC C++ compiler herunterladen und installieren k¨onnen.
1.6 TESTFRAGEN
17
Studentin, 07.05.2010 ”Das ist zwar alles sehr sch¨on - aber sehr verwirrend.
Wie bekomme ich mein Programm zum Laufen?” Ich gebe zu, ich bombardiere sie mit neuen Begriffen (IT slang). Schauen sie sich bitte noch
mal die Abb. 1.4 an. Dort sehen sie die einzelnen Schritte zur Erstellung
eines Programms. Ich erkl¨
are es mal step-by-step.
1. Quell-Datei: Zun¨
achst m¨
ussen sie eine Quell-Datei erstellen (oder eine
¨
aus den Ubungen
nehmen). Hierf¨
ur k¨onnen sie einen beliebigen Editor
nehmen (z.B. Notepad von Windows). Diese Datei hat die Endung
(extension) .cpp und enth¨alt die main() Funktion.
2. Kompilation: Im n¨
achsten Schritt muss diese Datei kompiliert, d.h.
in Maschinencode u
ur muss ein C++ Kompiler
¨ bersetzt werden. Hierf¨
(z.B. g++ von cygwin) installiert sein. Die cygwin Anweisung (also
auf der Kommandozeile im cygwin Fenster) ist: g++ main.cpp. Im
¨
Ergebnis (wenn alles gut gegangen ist, also keine Ubersetzungsfehler
aufgetreten sind) erhalten sie eine ausf¨
uhrbare Datei (executable),
normalerweise: a.exe.
3. Jetzt k¨
onnen wir das Programm starten mit ./a.exe von der Kommandozeile. Das ./ ist wichtig, um dem Betriebssystem mitzuteilen,
dass wir das Programm vom aktuellen Verzeichnis (wo a.exe liegt)
starten wollen. Viel Gl¨
uck.
1.6
Testfragen
1. Was bedeutet das ++ im Namen der Programmiersprache C++ ?
2. Ist C++ eine standardisierte Programmiersprache ?
3. Was ist der Unterschied zwischen C und C++ ?
4. Was sind sogenannte Programmier-Paradigmen ?
5. Welche verschiedenen Programmier-Paradigmen kennen sie und worin unterscheiden sie sich ?
6. Welches Paradigma verfolgen wir in der Vorlesung ?
7. Was ist objekt-orientierte Programmierung ?
8. Was ist ein Kompiler ?
9. Erkl¨
aren sie die einzelnen Schritte bei einer Kompilierung (s. Abb. 1.4).
¨
10. Welchen Kompiler benutzen sie f¨
ur die C++ Ubungen
?
11. Welche Funktion ben¨
otigt jedes C oder C++ Programm ?
18
12. Was ist der Typ einer Funktion ?
13. Was ist eine Parameterliste einer Funktion ?
14. Was ist der R¨
uckgabewert einer Funktion ?
¨
KAPITEL 1 EINFUHRUNG
Kapitel 2
Datentypen
Jede Programmiersprache bietet die Verwendung elementarer Datentypen an,
wie z.B. Ganzzahlen oder Gleitkommazahlen, logische Ausdr¨
ucke oder Zeichenketten. Die Besonderheit von objekt-orientierten (OO) Sprachen ist die Erstellung benutzerdefinierter Datentypen. Dies war schon in der Sprache C mit sog.
’typedef struct’ Typen m¨
oglich. OO Sprachen, wie C++, bieten aber noch mehr
an, die Verkn¨
upfung von benutzerdefinierten Datentypen mit den entsprechenden Methoden. Diese Konstrukte nennt man Klassen, aber darum geht es erst
im n¨
achsten Kapitel. Zun¨
achst m¨
ussen wir uns (kurz) mit den handels¨
ublichen
Datentypen herumschlagen.
2.1
Elementare Datentypen
¨
Die nachfolgende Tabelle zeigt eine Ubersicht
der elementaren Datentypen.
Typ
Wahrheitswerte
Zeichen
Ganzzahlen
Gleitpunktzahlen
Bezeichner
bool
char
wchar t
string
short
int
long
float
double
long double
Erl¨auterung
Wert kann true (=1) oder false (=0) sein
Zeichen, statische Zeichenketten
’wide character type’ (≥ 2 Byte)
Dynamische Zeichenketten
Ganze Zahlen mit geringer Genauigkeit
Ganze Zahlen mit hoher Genauigkeit
Ganze Zahlen mit sehr hoher Genauigkeit
Reelle Zahlen mit geringer Genauigkeit
Reelle Zahlen mit hoher Genauigkeit
Reelle Zahlen mit sehr hoher Genauigkeit
¨
Tabelle 2.1: Ubersicht
elementarer Datentypen
19
20
2.2
KAPITEL 2 DATENTYPEN
Speicherbedarf
Die unterschiedlichen Datentypen werden durch den Compiler verschieden verarbeitet und gespeichert (Gr¨oße des ben¨otigten Speicherplatzes).
Typ
bool
char
int
Speicherplatz
1 Byte
1 Byte
2/4 Byte
short
long
float
double
long double
2 Byte
4 Byte
4 Byte
8 Byte
10 Byte
Wertebereich
(weniger geht leider nicht)
-128 bis + 127 bzw. 0 bis 255
-32768 bis +32767 bzw.
-2147483648 bis + 2147483647
-32768 bis +32767
-2147483648 bis + 2147483647
± 3.4E+38, 6 Stellen Genauigkeit
± 1.7E+308, 15 Stellen Genauigkeit
± 1.7E+4932, 19 Stellen Genauigkeit
Tabelle 2.2: Speicherbedarf elementarer Datentypen
Der sizeof Operator ermittelt die ben¨otigte Speichergr¨oße f¨
ur einen bestimmten Datentypen, z.B. sizeof(float) = 4: eine einfach genaue Gleitkommazahl
¨
ben¨
otigt 4 Byte Speicher. Wir verwenden den sizeof Operator in der Ubung
E34.
2.3
Escape-Sequenzen
Escape-Sequenzen sind n¨
utzliche Helfer, z.B. zum Formatieren von Ausgaben
oder f¨
ur die Benutzung von Sonderzeichen in der Ausgabe.
Zeichen
\a
\b
\t
\n
\v
\r
\0
\”
\’
\?
\\
Bedeutung
alert (BEL)
backspace (BS)
horizontal tab (HT)
line feed (LF)
vertical tab (VT)
carriage return (CR)
end of string
”
’
?
\
Wirkung
Ausprobieren
eine Position zur¨
uck
horizontaler Tabulator
Zeilenumbruch
vertikaler Tabulator
Zeilenumbruch
Zeilenende
Zeichen
Zeichen
Zeichen
Zeichen
Tabelle 2.3: N¨
utzliche Escape-Sequenzen
Anmerkung:
Die Gr¨
oße eines Datentyps wird vom C++ Standard eigentlich nicht vorgegeben und kann Rechnerarchitektur und Compiler abh¨angig sein. In der Regel ist
2.4 TESTFRAGEN
21
der Speicherbedarf elementarer Datentypen aber gleich, z.B. double ben¨otigt
i.d.R. 8 Byte. Es gibt allerdings auch Ausnahmen, z.B. f¨
ur string. Die Klasse std::string geh¨
ort zur Standard-Bibliothek. Die Gr¨oße eines Strings ist
abh¨
angig von Rechnertyp, Betriebssystem und Compiler. Ein ’leerer’ String
kann zwischen 4 und 8 Byte lang sein.
2.4
Testfragen
1. Was ist der genaueste Datentyp in C++ ?
2. Wie groß ist der Speicherbedarf von einem string Datentyp ?
3. Mit welcher Anweisung k¨
onnen wir den Speicherbedarf von elementaren
Datentypen ermitteln ?
4. Was sind Escape-Sequenzen ?
5. Was ist der Unterschied zwischen den Escape-Sequenzen \n und \r ?
6. Was ist die C++ Entsprechung der Klasse cout f¨
ur einen Zeilenumbruch
?
Kapitel 3
Ein- und Ausgabe
Ein Programm (ob prozedural, modular, objekt-orientiert) ist eigentlich nichts
weiter als eine Datenverarbeitung zwischen einer Eingabe (Input) und einer
Ausgabe (Output). I und O k¨onnen mehr oder weniger schick gemacht sein:
1. I/O Standardger¨ate,
2. I/O Dateien,
3. Datenbanken (I) und Visualisierung (O).
Aus didaktischen Gr¨
unden m¨
ussen wir leider mit dem Langweiligsten - I/O
Standardger¨
ate - anfangen. Spannend wird’s, wenn Daten durch die Visualisierung ’lebendig’ werden. Die Abb. 3.1 zeigt eine professionelle Datenaufbereitung
einen Porenraummodells in unserem Labor f¨
ur wissenschaftliche Visualisierung
(TESSIN-VISLab) am UFZ in Leipzig.
Die iostream Klasse
Die Ein- und Ausgabe in C++ erfolgt mit sogenannten Str¨omen (streams). Die
I/O-Stream-Klassen (Abb. 3.2) bieten vielf¨altige M¨oglichkeiten, die wir uns in
¨
den nachfolgenden Ubungen
n¨aher anschauen.
22
23
.
Abbildung 3.1: Wissenschaftliche Visualisierung
ios
istream
ostream
iostream
Abbildung 3.2: I/O stream Klassen
Die Klasse iostream geht durch Mehrfachvererbung aus den Klassen istream
und ostream hervor. iostream stellt damit die Funktionalit¨at beider I/O Klassen zu Verf¨
ugung.
24
KAPITEL 3 EIN- UND AUSGABE
3.1
Die Standard-Streams
Es gibt vier Standard-Streams:
• cin: Standard-Eingabe u
¨ ber die Tastatur, Objekt der Klasse istream
• cout: Standard-Ausgabe auf dem Bildschirm, Objekt der Klasse ostream
• cerr und clog: zwei Objekte der Klasse ostream f¨
ur die Fehlerausgabe.
Exercise E3.1:
#include <iostream>
using namespace std;
int main()
{
int zahl;
cout << "Bitte eine ganze Zahl eingeben: ";
cin >> zahl;
cout << zahl << endl;
return 0;
}
Die Ein- >> und Ausgabeoperatoren << transportieren die Str¨ome von und zu
den Eingabe- bzw. Ausgabeger¨aten. Dabei formatieren sie die Datentypen (z.B.
¨
int in der Ubung
E3.1) entsprechend den Einstellungen der Klasse ios. Diese
Einstellungen k¨
onnen durch Flags ver¨andert werden (siehe n¨achsten Abschnitt).
3.2
Formatierte Ausgaben
Wir besch¨
aftigen uns mit der Gestaltung, d.h. Formatierung, von Ausgaben, eir
wollen die Bildschirmausgabe schick machen, z.B. in Tabellenform, dass alles
sch¨
on untereinander steht. Der zweite Aspekt der Formatierung ist die Genauigkeit von ausgegebenen Zahlenwerten.
3.2.1
Formatierte Ausgabe von Ganzzahlen
¨
In der nachfolgenden Ubung
besch¨aftigen wir uns mit den verschiedenen Ausgabem¨
oglichkeiten von ganzen Zahlen.
Exercise E3.2.1:
#include <iostream>
using namespace std;
int main()
{
3.2 FORMATIERTE AUSGABEN
25
int zahl;
cout << "Bitte eine ganze Zahl eingeben: ";
cin >> zahl;
cout << uppercase // f¨
ur Hex-Ziffern
<< " oktal \t\t dezimal \t hexadezimal \n "
<< oct << zahl << " \t\t "
<< dec << zahl << " \t\t "
<< hex << zahl << endl;
return 0;
}
3.2.2
Formatierte Ausgabe von Gleitpunktzahlen
¨
In der nachfolgenden Ubung
besch¨aftigen wir uns mit den verschiedenen Ausgabem¨
oglichkeiten von realen Zahlen.
Methoden
int precision(int n)
Wirkung
Genauigkeit wird auf n gesetzt
Exercise E3.2.2:
#include <iostream>
using namespace std;
int main()
{
double zahl;
cout << "Bitte eine Gleitkommazahl eingeben: ";
cin >> zahl;
cout.precision(7); // auf sieben Stellen genau
cout << "Standard: \t"
cout << "showpoint: \t" << showpoint
cout << "fixed: \t\t"
<< fixed
cout << "scientific: \t" << scientific
return 0;
<<
<<
<<
<<
zahl
zahl
zahl
zahl
<<
<<
<<
<<
endl;
endl;
endl;
endl;
}
3.2.3
Ausgabe von Speicherbedarf
¨
In dieser Ubung
benutzen wir den sizeof Operator, um den Speicherbedarf von
Standard Daten-Typen zu bestimmen.
Exercise E3.2.3:
#include <iostream>
26
KAPITEL 3 EIN- UND AUSGABE
using namespace std;
int main()
{
cout << "Type\tNumber of bytes\n";
cout << "-----------------------\n";
cout << "bool\t\t" << sizeof(bool) << endl;
cout << "char\t\t" << sizeof(char) << endl;
cout << "short\t\t" << sizeof(short) << endl;
cout << "int\t\t" << sizeof(int) << endl;
cout << "long\t\t" << sizeof(long) << endl;
cout << "float\t\t" << sizeof(float) << endl;
cout << "double\t\t" << sizeof(double) << endl;
cout << "long double\t" << sizeof(long double) << endl;
return 0;
}
3.3
Testfragen
1. Sind sie mit der Tab. 2.2 einverstanden ?
2. Welche Ein- und Ausgabeger¨ate kennen sie ?
3. Welche Klasse ben¨otigen wir f¨
ur die Standard-Ein- und Ausgabe ?
4. Was ist die Basis-Klasse f¨
ur alle Ein- und Ausgaben in C++ ?
5. Mit welcher Klasse k¨onnen wir sowohl Eingabe- als auch Ausgabestr¨ome
benutzen ?
6. Welche Include-Datei ist notwendig, um mit I/O-Str¨omen arbeiten zu
k¨
onnen ?
7. Wozu dient der Zusatz using namespace std; nach dem Include von
Standard-Klassen, wie I/O Streams ?
8. Was bewirken die Stream-Operatoren << und >> ?
9. Was bewirken die Flags oct, dec, hex f¨
ur die formatierte Ausgabe von
Ganzzahlen ? (ToDo)
10. Wie kann ich die Genauigkeit der Ausgabe von Gleikomma-Zahlen festlegen ?
11. Wie kann man den Speicherbedarf einer Variable ermitteln ? Schreiben
sie die C++ Anweisung f¨
ur die Berechnung des Speicherbedarfs f¨
ur eine
doppelt-genaue Gleitkomma-Zahl.
Kapitel 4
Klassen
source:
TU Dresden
Data abstraction
class CStudent
properties
...
methods
...
Instances
CStudent *m_std;
Abbildung 4.1: Das Klassen-Konzept - CStudent
27
28
KAPITEL 4 KLASSEN
Das Sprachelement der Klassen sind das entscheidende Kriterium von objektorientierten Konzepten und die objekt-orientierte Programmierung (OOP). Klassen sind eine Art Schablone f¨
ur einen benutzerdefinierten Datentypen. Dar¨
uber
hinaus enth¨
alt die Klasse neben den Daten auch alle Methoden (Funktionen),
um mit den Daten der Klasse operieren zu k¨onnen. Unser Beispiel f¨
ur Klassen,
das uns im Verlaufe der Vorlesung besch¨aftigen wird, ist - wie k¨onnte es anders sein - CStudent (Abb. 4.1). F¨
ur die Konzipierung von Klassen spielt die
Abstraktion der Daten einer Klasse eine besonders wichtige Rolle.
4.1
Daten-Abstraktion
Die Abb. 4.1 illustriert uns, dass eine Abstraktion von Daten (d.h. Eigenschaften) der Klasse Studenten eine durchaus vielschichtige Angelegenheit sein kann.
Eine Aufstellung von Daten / Eigenschaften, die es aus ihrer Sicht zu ber¨
ucksichtigen gilt, ist ihre n¨achste Hausaufgabe.
Der n¨
achste Block zeigt ihnen das Schema der Syntax der Klassen-Definition
CStudent. Das Schl¨
usselwort f¨
ur die Klassen-Definition ist class, der Name ist
CStudent. Der Klassen-Rumpf ist in geschweifte Klammer eingebettet. Wichtig
ist der Abschluss mit einem Semikolon. Wie bereits erw¨ahnt, eine Klasse enth¨alt
Daten (Eigenschaften) und Methoden (Funktionen) auf den Daten. Prinzipiell
geht diese Datenabstraktion auch mit anderen Sprachen wie C. A data construct
typedef struct {...} in C can be seen as an analogue to a C++ class.
Die C Version:
typedef struct
{
char* name_first;
char* name_last;
long matrikel_number;
} TDStudent;
TDStudent *student = NULL;
Die C++ Version:
class CStudent
{
data:
...
methods:
...
};
Bei der Namensgebung von Klassen wird oft ein ’C’ (CStudent) vorangestellt,
um die Bedeutung als Klasse (wesentlicher Baustein des Programm-Konzepts)
herauszustellen.
4.2 KLASSEN-DEKLARATION
29
Ein weiterer Vorzug von OO-Sprachen ist z.B. die Sichtbarkeit / Zugreifbarkeit
von Daten zu regeln. Der nachfolgende Block zeigt das Datenschutz-Konzept
von C++ (Sicherheitsstufen): Daten k¨onnen ¨offentlich sein (public) oder gezielt
f¨
ur ’Freunde’ verf¨
ugbar gemacht werden (protected) oder nur exklusiv f¨
ur die
eigene Klasse sichtbar zu sein (private).
class CStudent
{
private:
...
protected:
...
public:
...
};
4.2
Klassen-Deklaration
Im vorangegangenen Abschnitt haben wir uns mit der Datenabstraktion mittels
Klassen besch¨
aftigt. So sollte konsequenterweise jede Klasse auch ihre eigenen sorry - eigenen Quelldateien besitzen. Die Deklaration von Klassen erfolgt u
¨ blicherweise in einer sogenannten Header-Datei *.h. F¨
ur die Methoden / Funktionen der Klasse ist eine *.cpp Datei reserviert. F¨
ur uns bedeutet dies, zwei
Dateien anlegen:
• student.h - die Deklaration der Klasse CStudent
• student.cpp - die Methoden der Klasse CStudent
Um mit der Klasse arbeiten zu k¨
onnen, m¨
ussen wir das entsprechende HeaderFile inkludieren. Dies erfolgt mit der Anweisung #include ”student.h” am Anfang unseres Main-Files.
#include "student.h"
int main
{
return 0;
}
4.3
Instanzen einer Klasse
An dieser Stelle m¨
ochten wir unsere Eingangsgraphik (Abb. 4.1) erinnern. Instanzen sind Kopien einer Klasse mit denen wir arbeiten k¨onnen, dass heißt
30
KAPITEL 4 KLASSEN
diese bekommen echten Speicher f¨
ur ihre Daten (die nat¨
urlich f¨
ur jede Instanz
einer Klasse unterschiedlich sein k¨onnen).
Es gibt zwei M¨
oglichkeiten, Instanzen einer Klasse zu erzeugen:
#include "student.h"
void main()
{
// Creating an instances of a class - 1
CStudent m_std_A;
// Creating an instances of a class - 2
CStudent *m_std_B;
}
Der direkte und der mittels eines sogenannten Zeigers (hierf¨
ur gibt ein ExtraKapitel). Wir werden sehen, dass der zweite Weg oft der bessere ist, da wir z.B.
die Initialisierung und das Speichermanagement f¨
ur unsere Daten selber in die
Hand nehmen k¨
onnen. Dies k¨onnen wir mittels sogenannter Konstruktoren und
Destruktoren erledigen. Damit besch¨aftigen wir uns im n¨achsten Abschnitt.
Exercise E4.3:
#include "student.h"
#include <iostream>
using namespace std;
int main()
{
CStudent *m_std_cpp; // pointer to an instance
cout << "E41: Instances of classes" << endl;
cout << "What have we created?\t : " << m_std << endl;
cout << "What size has it?\t : " << sizeof(m_std) << endl;
TDStudent *m_std_c; // pointer to TD
return 0;
}
-> student.h
// Class definition
class CStudent
{
public:
protected:
private:
};
// Type definition
typedef struct
{
} TDStudent;
4.4 KONSTRUKTOR UND DESTRUKTOR
4.4
31
Konstruktor und Destruktor
Wohl die wichtigsten Methoden von Klassen sind deren Konstruktoren CStudent()
und Destruktoren ∼ CStudent(). Diese Funktionen haben den gleichen Namen
wie die Klasse selbst. Der nachfolgende Block zeigt die Deklaration unserer ersten beiden Klassen-Funktionen in der Header-Datei students.h.
class CStudent
{
public:
CStudent(); // constructor
~CStudent(); // destructor
};
Wie sehen die Konstruktor/Destruktor-Funktionen aus.
#include "student.h"
CStudent::CStudent()
{
}
CStudent::~CStudent()
{
}
Die Konstruktor/Destruktor-Funktionen werden ’automatisch’ aufgerufen beim
Erzeugen (¨
uber die Zeiger-Version) und Zerst¨oren der Klassen-Instanz:
• new ruft den dazugeh¨
origen Konstruktor auf,
• delete ruft den dazugeh¨
origen Destruktor auf.
Die Anwendung der Konstruktor/Destruktor-Funktionen ist im folgenden QuellcodeAbschnitt dargestellt.
Exercise E4.4:
#include <iostream>
using namespace std;
#include "student.h"
int main()
{
CStudent* m_std = new CStudent(); // instance using constructor
cout << "E44: Constructor of class CStudent" << endl;
cout << "What have we created? m_std\t : " << m_std << endl;
cout << "What size has it?\t : " << sizeof(m_std) << endl;
cout << "What have we created? &m_std\t : " << &m_std << endl;
cout << "What size has it?\t : " << sizeof(&m_std) << endl;
return 0;
}
32
4.5
KAPITEL 4 KLASSEN
Dateninitialisierung mit dem Konstruktor
Der Klassen-Konstruktor kann dar¨
uber hinaus auch zur Initialisierung von Daten f¨
ur die Klassen-Instanz benutzt werden. Ganz nebenbei schreiben wir unsere
erste Klassen-Funktion in der Quell-Datei der Klasse students.cpp. Wir initialisieren den Namen unseres ersten Studenten.
Exercise E4.5:
CStudent::CStudent()
{
// Initializations
name_first = "James";
name_last = "Bond";
}
Daf¨
ur m¨
ussen wir die notwendigen Klassen-Variablen (member variables) f¨
ur
den Namen bereitstellen. Praktischerweise ist es ratsam, die Daten und Methoden der Klasse zu trennen. Unsere Klassen-Deklaration nimmt langsam Gestalt
an ...
#include <string>
using namespace std;
class CStudent
{
// Data / Properties
public:
string name_first;
string name_last;
// Methods / Functions
public:
CStudent(); // constructor
~CStudent(); // destructor
};
F¨
ur die Namen benutzen wir die string Klasse von C++ (auch hierzu gibt’s
ein Extra-Kapitel). Um den Daten-Typ string aus dieser Klasse benutzen zu
k¨
onnen, m¨
ussen wir die Klasse wie folgt inkludieren.
#include <string>
using namespace std;
Exercise E4.5:
#include <iostream>
using namespace std;
#include "student.h"
4.6 DATENSCHUTZ
33
int main()
{
CStudent* m_std = new CStudent(); // instance using constructor
cout << "E45: Data initialisation by constructor of class CStudent" << endl;
cout << "m_std->name_first\t : " << m_std->name_first << endl;
cout << "m_std->name_last\t : " << m_std->name_last << endl;
delete(m_std);
return 0;
}
4.6
Datenschutz
Eine wichtige Eigenschaft der Sprache C++ ist die M¨oglichkeit, Daten unterschiedlich sichtbar zu machen. Eingangs des Kapitels haben wir gesehen, dass
es verschiedene Schl¨
usselw¨
orter gibt, um Variablen zu klassifizieren: public, protected und private. Daten des Typs ’public’ sind u
¨ berall sichtbar, aus sie kann
von u
¨berall im Programm zugegriffen werden - also auch ver¨andert werden. Dies
kann sehr schnell problematisch werden, wenn das Programm sehr groß ist oder
mehrere Programierer gleichzeitg entwickeln. Daten des Typs ’private’ sind nur
f¨
ur die eigene Klasse sichtbar, dass auf sie k¨onnen nur durch Klassen-eigene
Methoden zugegriffen werden. Private data sind f¨
ur andere Klassen verborgen.
Nat¨
urlich gibt es noch einen Kompromiss: Mit dem Schl¨
usselwort ’protected’
kann man gewisse Daten f¨
ur ’befreundete’ Klassen ¨offnen. Dies ist im Wesentlichen das Datenschutz-Konzept von C++.
¨
In der folgenden Ubung
sehen wir, wie man mit ’private’ data (Kontonummer)
umgehen kann. Die Variable bank account ist als private Typ deklariert.
class CStudent
{
public:
long GetBankAccount();
void SetBankAccount(long);
private:
long bank_account;
};
Die Zugriffsfunktion GetBankAccount() der Klasse CStudent gibt lediglich den
Wert der Variable zur¨
uck, ihr Typ ist nat¨
urlich public. Die Kontonummer kann
also zun¨
achst nicht von ’außen’ ge¨andert werden.
long CStudent::GetBankAccount()
{
return bank_account;
}
34
KAPITEL 4 KLASSEN
void CStudent::SetBankAccount(long new_bank_account)
{
bank_account = new_bank_account;
}
Nat¨
urlich l¨
asst sich auch eine Funktion schreiben, mit der man private Daten
von außen ¨
andern kann: SetBankAccount(long). Letztlich entscheidet der Programmierer, ob dieser Zugriff zul¨assig sein soll, wenn nicht gew¨
unscht, werden
die Get und Set Zugriffsfunktionen einfach nicht bereitgestellt.
¨
Die nachfolgende Ubung
zeigt zusammenfassend den Zugriff auf private Variablen von Außen.
Exercise E4.6:
int main()
{
CStudent* m_std = new CStudent(); // instance using constructor
cout << "E46: Data security - using private data" << endl;
cout << "m_std->GetBankAccount()\t : " << m_std->GetBankAccount() << endl;
m_std->SetBankAccount(987654321); // changing private data
cout << "m_std->GetBankAccount()\t : " << m_std->GetBankAccount() << endl;
delete(m_std);
return 0;
}
4.7 TESTFRAGEN
4.7
35
Testfragen
1. Geben sie eine Definition von C++ Klassen mit eigenen Worten (max 5
S¨
atze).
2. Was ist ein benutzerdefinierter Datentyp ?
3. Welches Datennschutz-Konzept gibt es f¨
ur Klassen ?
4. Wozu brauchen wir zwei Dateien f¨
ur Klassen, eine H (Header) Datei und
eine CPP (Quelltext) Datei ?
5. Was ist ein Inklude / Include ?
6. Was ist eine Instanz einer Klasse ?
7. Worin besteht der Unterschied zwischen den Anweisungen: CStudent m std 1
und CStudent* m std 2 ?
8. Was ist ein Konstruktor einer Klasse ?
9. Was ist das Gegenst¨
uck zum Klassen-Konstruktor ?
10. Wie k¨
onnen Daten / Variablen einer Klasse initialisiert werden ?
11. Schreiben sie den Quelltext f¨
ur den Klassen-Konstruktor und weisen sie
den Variablen name first und name last ihren eigenen Namen zu.
12. Was verbirgt sich hinter der Anweisung: CStudent* m std = new CStudent()
?
13. Was ist der Unterschied zwischen CStudent und CStudent() ?
14. Wie kann ich meine Daten gegen einen externen Zugriff sch¨
utzen ?
Kapitel 5
Strings
¨
Wir haben schon in mehreren Ubungen
den Datentyp string benutzt, ohne diesen
Datentyp etwas n¨
aher zu beleuchten. Dieses Vers¨aumnis soll in diesem Kapitel
nachgeholt werden.
5.1
Die Standardklasse string
String (in Deutsch Zeichenkette) ist vielmehr als nur ein Datentyp, string ist eine
Standard-Klasse in C++. String ist eine der genialsten Weiterentwicklungen des
C-Datentyps char, die das Hantieren mit Zeichen und Zeichenketten zu einem
Kinderspiel macht, na sagen wir mal - uns das Programmierleben erheblich
vereinfachen wird, wenn wir mit Zeichenketten operieren werden. So wird z.B.
der erforderliche Speicherplatz f¨
ur Zeichenketten automatisch reserviert und bei
Ver¨
anderungen angepasst.
Wenn wir strings benutzen wollen, m¨
ussen den Header der string-Klasse wie
folgt inkludieren.
#include <string>
// for using strings
using namespace std; // for using standard names
Wichtig ist auch die zweite Zeile using namespace std. Diese Anweisung besagt,
dass wir im folgenden Standard-Namen benutzen. Sonst m¨
ussten wir vor jeder
string-Operation noch den Zusatz std:: setzen. Zur Benutung von namespace f¨
ur
die Strukturierung und Kapselung von Programmteilen gibt es sp¨ater ein Extrakapitel (9.2.2). An dieser Stelle zeigen wir die Bedeutung von using namespace
std; in bew¨
ahrter Weise an einem Beispiel.
Sie haben sicher schon bemerkt, dass wir bei #include manchmal eckige Klammern <> und manchmal G¨ansef¨
ußchen ” benutzen. Wir schauen uns dies, wie
36
5.2 OPERATIONEN MIT STRINGS
37
gesagt, genauer im Kapitel 9.2.2 an. Hier nur soviel, dass mit eckigen Klammern
<> an Header-Dateien im Systemverzeichnis von C++ gesucht wird, w¨ahrend
” benutzerdefinierte, eigene Header (z.B. student.h) kennzeichnet und somit im
aktuellen Arbeitsverzeichnis (also ./) nachgeschaut wird.
5.2
Operationen mit strings
¨
Die nachfolgende Tabelle zeigt eine Ubersicht
der wichtigsten string Operationen, die wir in diesem Kapitel verwenden.
Methode
.append()
.c str()
.clear()
.compare()
.erase()
.find()
.insert()
.length()
.replace()
.resize()
.substr()
>>
<<
getline()
Erl¨
auterung
verl¨
angert den String
erzeugt Zeichenfeld mit dem Inhalt des Strings
l¨
oscht den Inhalt des Strings
vergleicht Strings
l¨
oscht Zeichen im String
sucht Zeichen in einem String
f¨
ugt in den String ein
ermittelt die L¨ange des Strings
ersetzt Zeichen im String
wichtig f¨
ur die Konvertierung von string zu char*
andert L¨
ange des Strings
¨
gibt einen Substring zur¨
uck
Eingabeoperator f¨
ur Strings
Ausgabeoperator f¨
ur Strings
liest Zeichen aus der Eingabe
Tabelle 5.1: string Methoden
5.2.1
Initialisieren von strings
Eine M¨
oglichkeit f¨
ur die Initialisierung von strings haben wir uns bereits in
der Exercise E4.5 angesehen bei der Verwendung von Klassen-Konstruktoren.
Der Standard-Konstruktor string() erzeugt einen leeren String. Eine zweite
M¨
oglickeit besteht direkt bei der Deklaration des strings, wie folgt:
Exercise E5.2.1:
string exercise("Exercise: string initialisation");
cout << exercise.length() << endl;
38
5.2.2
KAPITEL 5 STRINGS
Zuweisen von strings
¨
In der folgenden Ubung
schauen wir uns an, wie wir mittels Tastatureingabe
(Standard-Eingabe-Ger¨at) strings zuweisen und Teile von strings in andere kopieren zu k¨
onnen.
Exercise E5.2.2:
#include ... // Bitte f¨
ugen sie die notwendigen Header selbst ein
main()
{...
string eingabe;
string eingabe_anfang;
string message("Bitte geben Sie eine Zeile mit der Tastatur ein.
Schliessen Sie die Eingabe mit Enter ab");
//------------------------------------------------------------------cout << message << endl; // Ausgabe der Eingabeaufforderung
getline(cin,eingabe); // Eingabe einer Zeile u
¨ber Tastatur
eingabe_anfang(eingabe,0,10); // die ersten 10 Zeichen von eingabe werden
nach eingabe_anfang kopiert
cout << "Ihr Eingagetext: " << eingabe << endl;
cout << "Die ersten 10 Zeichen des Eingagetextes: " << eingabe_anfang << endl;
...}
5.2.3
Verketten von strings
Mit dem Operator + k¨onnen Strings miteinander verkn¨
upft werden und in einem
¨
neuen string name kopiert. In der folgenden Ubung
produzieren wird aus Vorund Nachnamen den ganzen Namen.
Exercise E5.2.3:
string name;
CStudent* m_std = new CStudent();
name = m_std->name_first + m_std->name_last;
// oder
name = m_std->name_first;
name += m_std->name_last;
Wie bekommen wir einen Zwischenraum (Leerzeichen) zwischen Vor- und Nachnamen ?
5.2.4
Vergleichen von strings
Oft sind Abfragen notwendig, ob gewisse Zeichenketten gefunden wurden, um
dann gewisse Operationen durchzuf¨
uhren. Hierf¨
ur bietet die String-Klasse mehrere M¨
oglichkeiten an, z.B. den exakten Vergleich (string::compare) oder einen
5.2 OPERATIONEN MIT STRINGS
39
¨
Teil von Zeichenketten (string::find). Die nachfolgende Ubung
zeigt, wenn der
Nachname BOND gefunden wurde, dann wird der Vorname auf JAMES gesetzt
(und nat¨
urlich der russische Geheimdienst informiert).
Exercise E5.2.4:
if(m_std->name_last.compare("BOND")==0)
{
m_std->name_first = "JAMES";
}
¨
Die nachfolgende Ubung
zeigt, wie ein Programm beendet werden kann, wenn
eine bestimmte Taste gedr¨
uckt wird. Hierf¨
ur werden einzelne Zeichen mit dem
Operator == verglichen.
string Taste("N");
while(Taste == "J")
{
cout << "Soll dieses Programm endlich beendet werden? (J/N)" << endl;
getline(cin,Taste);
}
cout << "Programm-Ende" << endl;
5.2.5
Suchen in strings
¨
Diese Ubung
zeigt ihnen, wie nach Zeichenketten in string suchen k¨onnen. Sie
sehen, je nach Sorgfalt des Programmierers haben sie eventuell schlechte Karten,
wenn ihr Vorname die Zeichenkette ’BON’ enth¨alt.
Exercise E5.2.5:
if(m_std->name_last.find("BON")!=string::npos)
{
m_std->name_first = "JAMES";
}
5.2.6
Einfu
¨ gen in strings
Nun benutzen wir die Einf¨
uge-Funktion von strings (string::insert), um Vorund Nachnamen zusammenzusetzen. Dabei ermitteln wir zun¨achst die L¨ange des
Vornamen mit string::length, setzen dann den Positionsz¨ahler pos um Eins hoch
(Leerzeichen zwischen Vor- und Nachnamen) und f¨
ugen dann den Nachnamen
mit string::insert ein.
Exercise E5.2.6:
40
KAPITEL 5 STRINGS
string name;
int pos;
if(m_std->name_first.find("JAMES")!=string::npos)
{
pos = m_std->name_first.length();
name.insert(pos+1,"BOND");
}
5.2.7
Ersetzen in strings
Eine weitere n¨
utzliche String-Funktion ist das Ersetzen von Zeichen. In der
¨
nachfolgenden Ubung
¨andern wir den Nachnamen. Dazu wird zun¨achst wieder
die L¨
ange des Vornamens mit string::length ermittelt und dann der neue Nachname eingef¨
ugt. So k¨onnen sie ihre Spuren verwischen ... ist auch praktisch bei
Namens¨
anderungen z.B. infolge Heiraten (Beachten sie, dass Triple-Namen wie
M¨
uller-Graf-Kleditsch nicht mehr zul¨assig sind).
Exercise E5.2.7:
string name;
int pos;
name = "JAMES" + " " + "CHRISTIE"
if(m_std->name_first.find("JAMES")!=string::npos)
{
pos = m_std->name_first.length();
name.replace(pos+1,"BOND");
}
Was passiert, wenn der neue Nachname l¨anger ist als der alte ?
5.2.8
L¨
oschen in strings
Nat¨
urlich k¨
onnen auch Zeichen in einem string gel¨oscht werden. Diese Funktion
passt den Speicherbedarf des gek¨
urzten Strings automatisch an.
Exercise E5.2.8:
string name;
int pos;
name = "JAMES" + " " + "CHRISTIE"
if(m_std->name_first.find("JAMES")!=string::npos)
{
pos = m_std->name_first.length();
name.erase(pos);
name.replace(pos+1,"BOND");
}
Abschliessend kommen wir zu zwei weiteren Punkten, (1) das Umwandeln von
C++ strings in C char und (2) das Auslesen von string Teilen.
5.2 OPERATIONEN MIT STRINGS
5.2.9
41
Umwandeln von strings in char
Manchmal ist es notwendig C++ strings in C char umzuwandeln (wir ben¨otigen
dies sp¨
ater, wenn wir mit der MFC Klasse CStrings f¨
ur grafische Benutzeroberfl¨
achen arbeiten). Die String-Methoden c str() und data() wandeln strings in
char um. Aufgepasst, ab char m¨
ussen wir uns selber um das Speichermanagement k¨
ummern.
fprintf(f," %s\n",name.c_str());
name.clear();
const char *char_string;
char_string = name.data();
5.2.10
Auswerten von Strings: Stringstreams
Stringstreams ... l¨
asst sich kaum aussprechen .. es handelt sich aber definitiv
nicht um stringdreams ... (sie erinnern sich an die Eingangsfolie der Vorlesung).
Stringstreams sind eine sehr n¨
utzliche Sache, damit lassen sich Eingabedaten
(von Tastatur und Datei) bequem als Stream auswerten. Um Stringstreams
¨
nutzen zu k¨
onnen, muss die Klasse sstream inkludiert werden. Die Ubung
zeigt,
wie man eine eingegebene Zeile (Vor- und Nachnahme) elegant zerlegen kann.
Dabei wird die eingebene Zeile zun¨achst in den stringstream kopiert, danach
wird input line wie ein normaler stream ausgelesen.
Exercise E5.2.10:
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
int main()
{
string name;
string name_first;
string name_last;
stringstream input_line;
cout << "Geben Sie bitte Ihren Namen (Vor- und Nachnamen) ein: ";
getline(cin,name);
input_line.str(name);
// Der Name wird nun zerlegt
input_line >> name_first;
cout << "Vorname:\t" << name_first << endl;
input_line >> name_last;
cout << "Nachname:\t" << name_last << endl;
input_line.clear();
return 0;
}
42
KAPITEL 5 STRINGS
5.3
Testfragen
1. Welche Klasse bietet uns C++ zur Verarbeitung von Zeichenketten an ?
2. Welchen Include ben¨otigen wir f¨
ur die Arbeit mit Zeichenketten ?
3. Wof¨
ur ist die Anweisung using namespace std n¨
utzlich ?
4. M¨
ussen wir selber Speicherplatz f¨
ur C++ Zeichenketten (Strings) reservieren ?
5. Wie k¨
onnen wir einen String, sagen wir mit der Zeichenkette ”Das ist eine
gute Frage”, initialisieren ?
6. Wie k¨
onnen wir zwei Strings, ihren Vor- und Nachnahmen, miteinander
verbinden ?
7. Mit welcher string Funktion kann ich Zeichenketten miteinander vergleichen ?
8. Schreiben sie eine Anweisung zum Vergleich der Klassen-Variable
m std− >name last mit ihrem Nachnamen ?
9. Mit welcher string Funktion kann ich Zeichenketten suchen ?
10. Schreiben sie eine Anweisung zum Suchen ihres Vornamens in der KlassenVariable m std− >name first ?
11. Mit welcher string Funktion kann ich Teile in Zeichenketten erstetzen ?
12. Wie k¨
onnen wir die L¨ange von Strings ermitteln ?
13. Schreiben sie die Anweisungen, um ihren Nachnamen in die Zeichenkette
”JAMES BOND” nach ”JAMES” einzuf¨
ugen ?
14. Was passiert, wenn ihr Nachname l¨anger als ”BOND” ist ?
15. Mit welcher string Funktion k¨onnen wir Zeichen in einem String l¨oschen ?
16. Wir haben gesehen, dass es verschiedene Daten-Typen f¨
ur Zeichenketten
in C, C++, MFC, .NET und Qt gibt. Zeichenketten geh¨oren zu den wichtigsten Daten-Typen bei der Programmierung. Wie k¨onnen wir einen C++
string in eine C Zeichenkette (char) umwandeln ?
17. K¨
onnen wir eine .NET Zeichenkette (String∧) in eine C++ Zeichenkette
(string) umwandeln ?
18. Was ist ein stringstream ?
19. Welchen Include ben¨otigen wir f¨
ur die Arbeit mit Stringstreams ?
Kapitel 6
Ein- und Ausgabe - II
Nachdem wir uns im Kapitel 3 bereits mit der Ein- und Ausgabe u
¨ ber die
Standard-Ger¨
ate (Tastatur und Bildschirm) besch¨aftigt haben, geht es in diesem
Teil um die Dateiverarbeitung.
6.1
Die fstream Klassen
Abb. 6.1 zeigt die Hierarchie der fstream Klassen.
ios
istream
ostream
iostream
ifstream
ofstream
fstream
Abbildung 6.1: Die fstream Klassen
Diese sind von den bereits bekannten ios stream Klassen abgeleitet.
43
44
KAPITEL 6 EIN- UND AUSGABE - II
• ifstream: ist von istream abgeleitet f¨
ur das Lesen von Dateien.
• ofstream: ist von ostream abgeleitet f¨
ur das Schreiben von Dateien.
• fstream: ist von iostream abgeleitet f¨
ur das Lesen und Schreiben von Dateien.
6.2
6.2.1
Arbeiten mit File-Streams
File-Streams anlegen
Er¨
offnungsmodus: Um eine Datei benutzen zu k¨onnen, muss diese zun¨achst
ge¨
offnet werden. Daf¨
ur gibt es verschiedene M¨oglichkeiten (siehe Tab. 6.1).
Flag
ios::in
ios::out
ios::app
ios::trunc
ios::ate
ios::binary
Funktion
Eine (existierende) Datei wird zum Lesen ge¨
offnet.
Eine Datei wird zum Schreiben ge¨
offnet.
Existierende Inhalte werden u
¨ berschrieben.
Die neuen Inhalten werden an die existierenden angeh¨
angt.
¨
Eine bestehende Datei wird beim Offnen
auf die L¨
ange 0 gek¨
urzt.
Schreib- und Leseposition werden auf das Dateiende gesetzt.
Schreib- und Leseoperationen werden im Bin¨
armodus ausgef¨
uhrt.
Tabelle 6.1: Er¨offnungsmodi f¨
ur Dateien
Die default Werte sind:
• ios::in f¨
ur ifstream
• ios::out | ios::trunc f¨
ur ofstream
6.2.2
File-Streams schließen
Wir wissen schon, dass es bei objekt-orientierten Sprachen immer zwei passende
Dinge gibt, z.B. Klassen-Konstruktoren und -Destruktoren. So ist zu erwarten,
dass es zu einer Methode ’Datei ¨offnen’ (open()) auch eine Methode ’Datei
schließen’ gibt (close()) (Tab. 6.4)
6.2.3
¨
Ubung:
Eine einfache Kopierfunktion
¨
In unserer ersten Ubung
zur Dateiverarbeitung schreiben wir eine einfache Kopierfunktion.
Exercise E6.2.3: Eine einfache file copy Funktion
6.2 ARBEITEN MIT FILE-STREAMS
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
//
//
//
//
for using
for using
for using
namespace
45
cout
ifstream / ofstream
string
for std functions
int main()
{
//---------------------------------------------------------------ifstream input_file;
// Instance of class ifstream
input_file.open("input_file.txt");
// Open file "text_file.txt"
string my_string;
// Instance of class string
input_file >> my_string;
// Reading a string from file
cout << my_string.data() << endl;
// Output of string to screen
//---------------------------------------------------------------ofstream output_file;
// Instance of class ifstream
output_file.open("output_file.txt"); // Open file "text_file.txt"
output_file << my_string;
// Writing a string to a file
//---------------------------------------------------------------return 0;
}
Die Ein- >> und Ausgabeoperatoren << formatieren die Datentypen (z.B. int
¨
in der Ubung
E6.2.3) entsprechend den Einstellungen der fstream Klasse. Diese
Einstellungen k¨
onnen durch Flags ver¨andert werden (siehe n¨achsten Abschnitt).
Die main() Funktion kann auch mit einer Parameterliste (int argc, char
*argv[]) versehen werden. Die Anzahl der Parameter (argc) wird automatisch
erkannt. MIt jedem Leerzeichen in der Tastatureingabe entsteht ein neuer Eingabeparameter (Abb. 6.2).
int main(int argc, char *argv[])
{
ifstream input_file;
input_file.open(argv[1]);
ofstream output_file;
output_file.open(argv[2]);
return 0;
}
//
//
//
//
Instance of class ifstream
Open file, name from cin
Instance of class ifstream
Open file, name from cin
Die Benutzung der main Funktion mit Eingabeparametern ist in der folgenden
Abbildung zu sehen.
Abbildung 6.2: Die main Funktion mit Parametern
46
6.2.4
KAPITEL 6 EIN- UND AUSGABE - II
¨
Ubung:
Ein einfacher Konverter
¨
Ihre Frage nach dem Sinn der Ubung
6.2.3 ist vollkommen berechtigt, wozu
ein Programm schreiben, um eine Datei zu kopieren. Das kann ich doch auch
mit dem Windows-Explorer oder mit cp file1 file2 machen. Richtig, aber
genauso funktionieren Kopierprogramme, Windows-Explorer ruft ’unser’ Ko¨
pierprogramm auf. Wenn wir auch nur kleine Anderungen
in unserer Datei vornehmen wollen (z.B. eine laufenden Nummer in jede Zeile einf¨
ugen), kann uns
der Windows-Explorer nicht mehr weiter helfen. Dies ist insbesondere dann
argerlich, wenn die Datei ziemlich groß ist ... Auch hier sagen sie zu Recht, eine
¨
Nummerierung in eine gr¨oßere Datei einf¨
ugen, das kann ich z.B. auch mit EX¨
CEL machen. In der n¨achsten Ubung
schreiben wir einen kleinen Konverter, also
genau was EXCEL im Hintergrund macht, wenn wir eine neue Spalte einf¨
ugen.
Exercise E6.2.4: Ein einfacher Konverter
int main()
{
//---------------------------------------------------------------ifstream input_file;
// Instance of class ifstream
input_file.open("input.txt");
// Open file "text_file.txt"
ofstream output_file;
// Instance of class ifstream
output_file.open("output.txt");
// Open file "text_file.txt"
//---------------------------------------------------------------char line[80];
int i=0;
while(input_file.getline(line,80))
// Loop condition
{
output_file << i << " " << line << endl;
i++;
// Incrementor (+1)
}
//---------------------------------------------------------------return 0;
}
Unser Konverter macht nichts anderes, als die Datei input.txt zu ¨offen, nacheinander alle Zeilen lesen und am Anfang der Zeile eine Nummer (i) einzuf¨
ugen
und dann in die neue Datei output.txt zu schreiben.
¨
Was ist neu bei dieser Ubung.
C++ Ding
while()
i++
Was tut’s
eine Kontrollstruktur f¨
ur Schleifen
(solange der Ausdruck in () wahr (true) ist
wird die Schleife ausgef¨
uhrt)
der Inkremetor (z¨ahlt Eins hoch)
Tabelle 6.2: C++ news
6.2 ARBEITEN MIT FILE-STREAMS
47
Alle benutzten fstream Methoden finden sie in Tab. 6.4.
6.2.5
Einschub: Erstes Arbeiten mit MS VC++
Wir haben den Editor von MS VC++ ja schon mehrfach benutzt, da die Syntax
¨
des Quelltextes sehr sch¨
on angezeigt wird (Abb. 6.3). Uberhaupt
ist MS VC++
ein sehr sch¨
ones Entwicklungssystem f¨
ur Programmentwicklung ... Wir f¨
uhren
¨
die Ubung
E6.2.4 jetzt mal mit MS VC++ aus.
Abbildung 6.3: Der MS VC++ Editor
Standardm¨
aßig werden folgende Einf¨arbungen benutzt f¨
ur
• Keywords: Blau
• Kommentare: Gr¨
un
• Normaler Quelltext: Schwarz
• Includes: Rot
48
KAPITEL 6 EIN- UND AUSGABE - II
• Zeichenketten: Rot
Ich bin mir ziemlich sicher, dass man in einem gut versteckten MS VC++ Menupunkt alles selber einstellen kann ...
Highlighting of sytax ... ist nur eines der sehr n¨
utzliches features (langsam gleiten
wir in IT slang ab). Um MS VC++ richtig nutzen zu k¨onnen, m¨
ussen wir
ein sogenanntes Projekt anlegen (mal sehen, ob ihre Begeisterung danach noch
anh¨
alt). Die Schritte f¨
ur die Projekterstellung finden sie in der Anlage (Abschn.
??) ... Nachdem das Projekt angelegt ist, k¨onnen wir damit arbeiten.
¨
Abbildung 6.4: Ubersetzen
sie das Projekt mit F7 (build solution)
Abbildung 6.5: Das Debug Verzeichnis
6.2 ARBEITEN MIT FILE-STREAMS
49
MSVS legt allerhand Zeug’s an. Das executable finden sie im Unterverzeichnis
Debug und kann nat¨
urlich mit einem Doppelklick gestartet werden. Wir starten
die Konsolenanwendung aus MSVS mit Ctrl-F5 (Abb. 6.6).
Abbildung 6.6: Starten der Konsolenanwendung mit Ctrl-F5 oder MenuAuswahl (Start without debugging)
¨
Hier wartet schon die erste Uberraschung
auf uns: pwd wird nicht erkannt und
wir werden aufgefordert eine Zeit einzugeben (Abb. 6.7).
Abbildung 6.7: Das Debug Verzeichnis
Was ist passiert ?
• pwd ist ein Linux-Befehl, den kennt der Windows-Compiler nicht.
• time gibt es auch als DOS-Befehl, hat aber eine ganz andere Bedeutung:
nicht Ausgabe der Zeit sondern Zeit ¨andern.
Wir sehen also, dass unser Quellcode von verschiedenen Compilern unterschiedlich interpretiert wird.
50
KAPITEL 6 EIN- UND AUSGABE - II
.
Abbildung 6.8: Der Windows bereinigte Quelltext
Sie sehen ’Sch¨
onheit’ hat auch ihren Preis ... dennoch die Funktionalit¨at der MS
VC++ Entwicklungsumgebung, das muss man neidlos anerkennen, ist einfach
Klasse.
6.3
File-Streams und Klassen
Wir wollen eine Lesefunktion f¨
ur die Klasse CStudent schreiben. Bevor wir
damit beginnen, m¨
ussen wir uns Gedanken u
ur die
¨ ber eine geeignete Struktur f¨
Darstellung eines CStudent Datensatzes in einer Datei machen. Der Vorschlag
f¨
ur die Strukturierung von Datens¨atzen ist die Benutzung von Schl¨
usselw¨ortern
zur Trennung von Datenbl¨ocken, z.B.
#STUDENT
$NAME_FIRST
James
$NAME_LAST
Bond
...
#STOP
Wir benutzen zwei verschiedene Symbole f¨
ur Schl¨
usselw¨orter:
6.3 FILE-STREAMS UND KLASSEN
51
• keyword # : zur Trennung von Datens¨atzen f¨
ur eine Instanz von CStudent,
• subkeyword $ : zur Identifizierung der einzelnen Daten f¨
ur die CStudent
Instanz.
• #STOP zeigt das Ende der Datenbasis an. (Eigentlich w¨are dies nicht
n¨
otig, da das Dateiende auch mit dem Parameter eof (end-of-file) abgefragt werden kann. Wir werden aber sehen, dass mit #STOP einiges
einfacher zu programmieren ist.)
Exercise E6.3: Implementierung der CStudent Lesefunktion
ios::pos_type CStudent::Read(ifstream& input_file)
{
//---------------------------------------------------------------------string input_line;
char buffer[256]; // MAX_LINE
ios::pos_type position;
//---------------------------------------------------------------------while(true)
{
position = input_file.tellg();
input_file.getline(buffer,256);
input_line = buffer;
if(input_line.size()<1) // empty line
continue;
// Dealing with keywords
if(input_line.find(’#’)!=string::npos) // keyword found
return position;
// Dealing with subkeywords
if(input_line.find("$NAME_FIRST")!=string::npos)
{
input_file.getline(buffer,256);
input_line = buffer;
name_first = input_line;
}
if(input_line.find("$NAME_LAST")!=string::npos)
{
input_file >> name_last;
}
if(input_line.find("$subkeyword")!=string::npos)
{
input_file >> member;
}
}
//---------------------------------------------------------------------return position;
}
52
KAPITEL 6 EIN- UND AUSGABE - II
Der Lesealgorithmus funktioniert wird folgt: Nach dem Auffinden eines Schl¨
usselworts #STUDENT, wird in einer while Schleife nach subkeywords ($) gesucht,
wenn gefunden, werden der CStudent Instanz die Werte aus der Eingabedatei
zugewiesen (also die Namen). Wenn das n¨achste Schl¨
usselwort (#STUDENT
oder #STOP) gefunden wird, geht’s mit der vorletzten Position raus aus der
Funktion. Die vorletzte position ist wichtig, damit die letzte Zeile sp¨ater nochmal gelesen werden kann, um das Schl¨
usselwort auswerten zu k¨onnen ...
Die Implementierung der main Funktion, in der die CStudent::Read() Funktion
aufgerufen wird, ist im folgenden Block dargestellt.
#include <iostream>
#include <fstream>
#include <string>
#include "student.h"
using namespace std;
//
//
//
//
//
for
for
for
for
for
using cout
using ifstream / ofstream
using string
using CStudents
std functions
int main()
{
//---------------------------------------------------------------// File handling
ifstream input_file; // ifstream instance
input_file.open("data_set.txt");
if(!input_file.good())
// Check is file existing
{
cout << "! Error in STD::Read: file could not be opened" << endl;
return 0;
}
input_file.seekg(0L,ios::beg);
// Rewind file
//---------------------------------------------------------------CStudent* m_std = new CStudent();
// CStudent instance
m_std->Read(input_file);
//---------------------------------------------------------------input_file.close();
return 0;
}
Die main Funktion besteht aus zwei Teilen, dem File-Handling und dem Aufruf
der Lesefunktion. Beim File-Handling wird der stream aus der Datei data set.txt
ge¨
offnet, anschließend erfolgt der Test, ob das File erfolgreich ge¨offnet werden
konnte; wenn nicht, wir die main Funktion sofort beendet.
¨
Was ist neu bei dieser Ubung.
Wir benutzen den Referenz-Operator & (Kapitel 7) als Parameter der Funktion
CStudent::Read(). Eine Referenz ist eigentlich nicht anderes als ein anderer
Bezeichner (Alias) f¨
ur eine bereits existierende Instanz eines Objekts. Es kann
also mehrere solcher Referenzen geben und vor Benutzung einer Referenz muss
die Instanz des Objekts physikalisch (also speicherm¨aßig) vorhanden sein, sonst
’crashed’ unser Programm.
6.4 FSTREAM METHODEN
53
C++ Ding
ifstream& input file
Was tut’s
eine Reference auf ein Objekt
wird in Kapitel 7 ausf¨
uhrlich abgehandelt
Tabelle 6.3: C++ news
6.4
fstream Methoden
Die bisher benutzten fstream Methoden sind in der Tab. 6.4 zusammengestellt.
Methode
open()
good()
seekg(pos,ios::beg)
seekg(0L,ios::beg)
tellg()
getline(buffer,256)
close()
>>
<<
Funktion
offnet die Datei
¨
¨
tested erfolgreiche Offnung
der Datei
geht zur Position pos in der Datei
spoolt zum Dateianfang zur¨
uck
merkt sich die aktuelle Position im stream
holt eine Zeile der L¨
ange 256 (Zeichen) aus dem stream
und kopiert diese in buffer
schließt Datei
Eingabeoperator f¨
ur Dateien
Ausgabeoperator f¨
ur Dateien
Tabelle 6.4: fstream Methoden
Die string Auswertung spielt bei der Lesefunktion eine wichtige Rolle, daher haben wir uns wir uns im vorangegangenen Kapitel mit der string Klasse besch¨aftigt.
54
KAPITEL 6 EIN- UND AUSGABE - II
6.5
Testfragen
1. Was ist die Basis-Klasse f¨
ur alle Ein- und Ausgaben in C++ ?
2. Was sind die C++ Klassen f¨
ur das Lesen und Schreiben von Dateien ?
3. Welchen Include ben¨otigen wir f¨
ur das Arbeiten mit I/O File-Klassen ?
4. Was sind die Standard-Flags f¨
ur File-Streams (Lesen und Schreiben) ?
5. Mit welchem Flag k¨onnen wir zu schreibende Daten an eine existierende
Datei anh¨
angen ?
6. Was ist der Unterschied zwischen ASCII- und Bin¨ar-Formaten ?
7. Mit welchem Flag k¨onnen wir Daten in einem Bin¨ar-Format schreiben ?
Mit welcher Anweisung wird ein File ge¨offnet ? Mit welcher Anweisung
wird ein File geschlossen ?
8. Was bewirken die Stream-Operatoren << und >> ?
9. Wie k¨
onnen wir mit Dateinamen in unserem Hauptprogramm main(...)
arbeiten ?
10. Welche Anweisung ben¨otigen wir f¨
ur die Erzeugung einer Instanz f¨
ur einen
Eingabe-Strom ?
11. Welche Anweisung ben¨otigen wir f¨
ur die Erzeugung einer Instanz f¨
ur einen
Ausgabe-Strom ?
12. F¨
ur die Erstellung einer Datenbank ist es wichtig einzelnen Datens¨atze zu
trennen. Wie k¨
onnen wir soetwas in der Datenbank-Datei bewerkstelligen
?
13. Ist es wichtig das Ende einer Datenbank-Datei, z.B. mit einem Schl¨
usselwort #STOP, zu markieren ?
¨
14. Mit welcher Abfrage k¨onne wir pr¨
ufen, ob die Offnung
einer Datei erfolgreich war ?
15. Mit welcher Anweisung k¨onnen wir die aktuell gelesene Position in einer
ge¨
offneten Datei abfragen ?
16. Mit welcher Anweisung k¨onnen wir zu einer bestimmten Position in einer
ge¨
offneten Datei springen ?
17. Mit welcher Anweisung k¨onnen wir eine komplette Zeile aus ge¨offneten
Datei auslesen ?
Kapitel 7
Referenzen und Zeiger
Referenzen und Zeiger (pointer), d.h. die Symbole & und * sind uns bereits
mehrfach begegnet, z.B. in der Parameterliste der main() Funktion ... Generell
k¨
onnen Zeiger und Referenzen als einfache Variable, Parameter oder R¨
uckgabewert (return) einer Funktion auftauchen.
¨
In der Ubung
E6.3 haben wir bereits mit Referenzen gearbeitet und festgestellt,
dass Referenzen eigentlich nichts anderes als andere Bezeichner (Alias) f¨
ur eine
bereits existierende Instanz eines Objekts sind. Es kann also mehrere solcher
Referenzen geben. Bei der Definition eines Zeigers wird also kein neuer Speicher reserviert. Die Instanz des Objekts muss physikalisch (also speicherm¨aßig)
nat¨
urlich vorhanden sein, sonst ’verabschiedet’ sich unser Programm gleich wieder.
x
&ref_x
Referenz auf
das Objekt
Objekt
im Speicher
Abbildung 7.1: Referenzen auf Objekte
55
x
y
56
KAPITEL 7 REFERENZEN UND ZEIGER
7.1
7.1.1
Referenzen
Das Call-by-reference Prinzip - Referenzen als Parameter
Def: Eine Referenz ist nichts anderes als ein anderer Name (Alias) f¨
ur ein bereits
existierendes Objekt. Bei der Definition einer Referenz wird also kein neuer
Speicherplatz f¨
ur das Objekt belegt (außer nat¨
urlich die 4 Byte f¨
ur die Referenz
selbst).
Die Abb 7.2 soll das Konzept des Referenzierens noch einmal verdeutlichen.
• x ist die Instanz eines Datentyps T
• &ref x ist eine Referenz (Verweis) auf x
¨
In der ersten Ubung
sehen die Definition von Referenzen und Zeigern im Quelltext
¨
Ubung:
E7.1.1
double x = 1.23456789;
double* ptr_x;
double& ref_x = x; // initialisation is needed
¨
Die Bildschirmausgabe der ersten Ubung
zeigt Folgendes:
Abbildung 7.2: Referenzen auf Objekte
Eine Referenz (ref x) muss bei der Definition initialisiert werden (mit x), sonst
bekommen sie eine Fehlermeldung beim Kompilieren.
Der Referenztyp-Parameter (&) ist ein Aliasname f¨
ur das ’richtige’ Argument.
Beim Aufruf der Funktion wird der Referenz-Parameter mit dem Objekt initialisiert. Die Funktion arbeitet also direkt mit dem von außen u
¨ bergebenen Argu¨
ment. Das ’Call-by-reference’ Prinzip ist sozusagen eine Ubergabe-von-Außen.
Wir schauen uns dies mal an bei der CStudent-Lesefunktion aus der letzten
Vorlesung.
¨
Ubung:
E7.1.1
7.2 ZEIGER
57
Definition:
CStudent::Read(ifstream& ref_input_file)
Aufruf:
ifstream input_file;
CStudent* m_std = new CStudent();
// CStudent instance
m_std->Read(input_file);
Was passiert ? Beim Aufruf der Lese-Funktion Read wird die Adresse des ifstream
Objekts (input file) an die Funktion u
¨bergeben. Das heisst die Lese-Funktion
arbeitet intern mit dem ’richtigen’ Objekt. ’Call-by-reference’ Prinzip erm¨oglicht
es also der Funktion einen Zugriff auf Daten des Aufrufers.
Beim sogenannten ’Call-by-value’ Prinzip k¨onnen Funktions-Argumente innerhalb der Funktion nicht ge¨
andert werden.
7.1.2
Referenzen als Ru
¨ ckgabe-Wert
Referenzen auf Objekte k¨
onnen auch R¨
uckgabe-Werte von Funktionen sein.
¨
Ubung: E7.1.2 (aus [5])
Definition:
string& message()
{
static string m_str("Vorsicht Speicher-Falle");
return m_str;
}
Aufruf:
!!! Das Objekt muss nach dem Verlassen der Funktion noch existieren
¨
Was ist neu bei dieser Ubung.
C++ Ding
static
Was tut’s
Speicherklasse: der Speicher f¨
ur das Objekt bleibt w¨ahrend
der gesamten Programmausf¨
uhrung bestehen,
wird in Kapitel 7.3 ausf¨
uhrlich abgehandelt.
Tabelle 7.1: C++ news
7.2
Zeiger
Zeiger sind eine der Grundideen moderner Programmiersprachen. Dabei arbeitet man nicht direkt mit den Daten-Bl¨ocken im Speicher sondern mit deren
Adressen. Dies macht insbesondere Sinn, wenn es um große Daten-Objekte geht
58
KAPITEL 7 REFERENZEN UND ZEIGER
oder bei Objekten, die erst zur Laufzeit angelegt werden (z.B. Vektoren, Listen, Strings). Das Klassen-Prinzip unterst¨
utzt die Zeigertechnik optimal, da
die Klasse ihre Daten ja selber verwaltet (siehe Klassenkonstruktur) Der Zeiger
(pointer) auf ein Objekt repr¨asentiert dessen Adresse und Daten-Typ.
7.2.1
Definition von Zeigern
¨
Die nachfolgende Ubung
zeigt, wie wir Zeiger definieren und mit ihnen arbeiten
k¨
onnen. F¨
ur den Zugriff auf Zeiger gibt es den sogenannten Verweisoperator ’*’.
¨
Ubung:
E7.2 (aus [5])
int main()
{
int i, *ptr_i; // Definitionen
i = 100;
// Zuweisung
ptr_i = &i;
// Dem Zeiger wird die Adresse der integer Variable i
// zugewiesen
*ptr_i += 1;
// Die integer Variable i wird um Eins erh¨
oht (i += 1;)
}
⇒Geben sie Werte und Adressen der Integer-Variable i und den Zeiger auf i
(i ptr) aus.
Unabh¨
angig vom Daten-Typ ist der ben¨otigte Speicher f¨
ur eine Zeigervariable
immer gleich groß - der zur Speicherung ben¨otigte Platz f¨
ur die Adresse des
Objekts (4 Byte auf einer 32-Bit-Rechner-Architektur, siehe auch Abb. 7.2).
¨
Was ist neu bei dieser Ubung.
C++ Ding
*ptr
i*i
Was tut’s
Verweisoperator (un¨ar: ein Operand)
Multiplikations-Operator (bi¨ar: zwei Operanden)
Tabelle 7.2: C++ news: Operatoren
7.2.2
NULL Zeiger
Wir haben gesehen, dass Referenzen auf Daten-Objekte zwingenderweise initialisiert werden m¨
ussen (sonst streikt der Kompiler). Zeiger m¨
ussen eigentlich
nicht initialisiert werden, ihnen wird bei der Definition eine ’vern¨
unftige’ Adresse zu gewiesen. Dies bedeutet noch lange nicht, dass sich hinter dieser Adresse
etwas Vern¨
unftiges verbirgt. Daher ist es ratsam, auch Zeiger zu initialisieren,
um Nachfragen zu k¨
onnen, ob sie tats¨achlich auf existierende Objekte zeigen.
Zum Initialisieren von Pointern gibt es den NULL-Zeiger.
7.3 ZEIGER UND ARRAYS
59
double* ptr_x = NULL;
ptr_x = &x;
if(!ptr_x) cout << "Warning: ptr_x does not have a meaningful adress";
Der linke Operand der Operators = muss immer auf eine ’sinnvolle’ Speicherstelle verweisen. Dieser wird daher auch als so genannter L-Wert (L(eft) value)
bezeichnet. Wenn eine Fehlermeldung ’wrong L-value’ erscheint, wissen sie, dass
keine ’sinnvolle’ Adresse vergeben wurde, dies spricht wiederum f¨
ur eine Initialisierung von Zeigern mit Zero-Pointer.
7.2.3
Zeiger als Parameter
Der Verweisoperator ist uns unl¨
angst schon mal begegnet bei der erweiterten
main() Funktion mit Eingabeparametern: int main(int argc, char* argv[])
7.3
Zeiger und Arrays
Wie bereits gesagt, die Verzeigerungs-Technik ist eine der Besonderheiten von
objekt-orientierten Sprachen, wie z.B. von C++. Mit solchen Pointern k¨onnen
wir auch gr¨
oßere Daten-Objekte wie Vektoren verwalten. Die zentrale Idee ist:
Wenn Startpunkt (id Adresse) und L¨ange des Vektors bekannt sind, wissen wir
eigentlich alles und k¨
onnen auf alle Vektor-Daten zugreifen.
7.3.1
Statische Objekte
Bei der Einf¨
uhrung der String-Klasse hatten wir bereits mit Zeichenketten zu
tun. Aus der Sicht des Speichers ist eine Zeichenkette ein Vektor der eine bestimmte Anzahl von Zeichen enth¨alt. Vektoren k¨onnen nat¨
urlich f¨
ur (fast) alle
Datentypen definiert werden. Im n¨achsten Kapitel (8) besch¨aftigen wir uns mit
sogenannten Containern, damit k¨onnen z.B. Vektoren, Listen etc. f¨
ur ganze
Klassen generiert werden.
char Zeichenkette[80];
int iVektor[50];
double dVektor[50];
7.3.2
Dynamische Objekte
Bisher haben wir uns fast ausschließlich mit Datentypen besch¨aftigt, deren
Speicherbedarf bereits w¨
ahrend der Kompilierung fest steht und reserviert wird
(bis auf Strings-Objekte). Es gibt aber auch die M¨oglichkeit, den Speicherbedarf w¨
ahrend der Programmausf¨
uhrung zu ¨andern - dies geht mit dynamischen
Daten-Objekten. Die werden wir folgt deklariert.
60
KAPITEL 7 REFERENZEN UND ZEIGER
char* Zeichenkette;
int* iVektor;
double* dVektor;
Nun m¨
ussen wir uns allerdings selber um die Speicherreservierung k¨
ummern.
¨
Dies erfolgt mit dem new-Operator und wird in der n¨achsten Ubung
gezeigt.
Wir ahnen schon, wenn es etwas zum Vereinbaren von Speicher gibt, muss es
wohl auch das Gegenst¨
uck - freigeben von Speicher - geben. Nat¨
urlich habe sie
Recht. Dies erledigt der delete-Operator.
double* dVektor;
dVektor = new double[1000];
delete [] dVektor;
Die Anwendung beider Operatoren zum Speichermanagement sowie eine M¨oglich¨
keit, den verbrauchten Speicher zu messen, werden in der folgenden Ubung
gezeigt.
¨
Ubung:
E7.3.2
#include <iostream> // for using cout
#include <malloc.h> // for using malloc_usable_size
using namespace std;
int main()
{
char* Zeichenkette;
// Definitions
long size_memory;
// Auxiliary variable for memory size
Zeichenkette = new char[1000]; // Memory allocation
size_memory = malloc_usable_size(Zeichenkette); // calculation of memory
delete [] Zeichenkette;
// Memory release
return 0;
}
HomeWork: HW7.3.2
Schreiben sie ein kleines Programm, mit der sie den ben¨otigten Speicher ermitteln k¨onnen und pr¨
ufen sie, ob die Freigabe des Speichers funktioniert hat.
Zeiger k¨
onnen auch verschachtelt werden: Zeiger auf Zeiger ... Damit lassen sich
mehrdimensionale Datenstrukturen schaffen, z.B. Matrizen.
7.4
Summary
Das Verstehen und Arbeiten mit Zeigern und Referenzen ist nicht ganz einfach und braucht eine ganze Zeit der praktischen Anwendung. Der *Operator
7.4 SUMMARY
61
**matrix
*matrix[0] *matrix[1] *matrix[2]
*matrix[1][0]
*matrix[1][1]
*matrix[1][2]
Abbildung 7.3: Die Definition einer Matrix mittels Pointer
kann beispielsweise als Zeiger auf etwas und gleichzeitig f¨
ur dynamische Vektoren benutzt werden. Dies scheint zun¨achst absolut verwirrend zu sein, beim
¨
genaueren Uberlegen
aber: * ist lediglich die Startadresse f¨
ur den Vektor. Merken sie sich erst einmal nur, dass es geschickter (und schneller) ist, nicht mit
den Daten-Objekten direkt sondern mit Verweisen darauf (also deren Adressen) zu arbeiten. Die nachfolgende Tabelle und Abbildung sollen das Thema
’Referenzen und Zeiger’ noch einmal illustrieren.
Syntax
double x
double* ptr
double& ref
double* dVektor
Bedeutung
Definition einer doppelt-genauen Gleitkommazahl
(Speicherbedarf 8 Byte)
Zeiger auf eine doppelt-genauen Gleitkommazahl
(Speicherbedarf 4 Byte)
Referenz auf eine doppelt-genaue Gleitkommazahl
(Speicherbedarf 4 Byte)
Zeiger auf einen Gleitkommazahl-Vektor
Tabelle 7.3: Zeiger und Referenzen
ptr_x
&ptr_x
Adresse von ptr_x
x
&x
ptr_x
Adresse von x
Wert von ptr_x
x
*ptr_x
Wert von x
Abbildung 7.4: Referenzen und Zeiger (nach [5])
62
KAPITEL 7 REFERENZEN UND ZEIGER
7.5
Testfragen
1. Was ist &x ? (x ist ein beliebiger Datenobjekt T, z.B. eine Gleitkommazahl: double x)
2. Was ist eine Referenz &ref?
3. Was bedeutet die Anweisung: &ref = x?
4. Erkl¨
aren sie kurz (mit eigenen Worten) das Zeiger-Konzept in C++?
5. Was bewirkt der NULL Zeiger, d.h. *ptr = NULL ?
6. Was bedeutet die Anweisung: ptr = &x?
7. M¨
ussen Referenzen (&) und Zeiger (*) auf Daten-Objekte initialisiert werden ?
8. Was bewirkt die Definition long l[1000] speichertechnisch ?
9. Wie groß ist der Speicherbedarf des statischen Datenobjekts long l[1000]
?
10. Wie groß ist der Speicherbedarf des dynamische Datenobjekts long* ptr l
= new long[1000] ?
11. Woher kommt der Unterschied (4 Byte auf einem 32Bit Rechner) im
Speicherbedarf zwischen statischen und dynamischen Datenobjekten.
12. Zusatzfrage: Was bedeutet die Definition **ptrptr (Zeiger auf Zeiger), was
f¨
ur ein Datenkonstrukt entsteht ?
Kapitel 8
Container
Wir haben bereits mit der String-Klasse gesehen, dass C++ neben der Basisfunktionalit¨
at einer Programmiersprache auch sehr n¨
utzliche Erweiterungen,
wie das Arbeiten mit Zeichenketten, anbietet. Diese Erweiterungen geh¨oren
zum Standard von C++, geh¨
oren also zum ’Lieferumfang’ des Compilers dazu
und heißen daher auch Standard-Klassen. Diese Klassen bilden die sogenannte
Standard-Bibliothek (STL - STandard Library).
In diesem Kapitel besch¨
aftigen wir uns mit sogenannten Containern mit denen Daten organisiert, gespeichert und verwaltet werden k¨onnen, z.B. Listen
und Vektoren. In der Abb. 8.1 sind die wichtigsten Elemente der Container
dargestellt. Der Begriff Container soll verdeutlichen, dass Objekte des gleichen
Typs z.B. in einer Liste gespeichert werden. Und wie immer bei Klassen, werden
nat¨
urlich auch die Methoden f¨
ur den Zugriff oder die Bearbeitung von diesen
Objekten bereitgestellt. Die Speicherverwaltung f¨
ur Container-Elemente erfolgt
dynamisch zur Laufzeit (siehe Kapitel Speicherverwaltung). Die Abb. 8.1 zeigt
auch, welche verschiedenen Typen von Containern es gibt:
Sequentielle Container: sind z.B. Vektoren, Listen, Queues und Stacks. Vektoren sind Felder (arrays) in denen die einzelnen Elemente nacheinander
angeordnet sind. Bei einer Liste kennt jedes Element nur seine Nachbarn (Vorg¨
anger- und Nachfolgeelement). Queues (wir kennen dies von
Druckern) sind Warteschlangen, die nach dem FIFO-Prinzip (first in, first
out) funktionieren. Das heißt, dass zuerst eingef¨
ugte Element wird auch
zuerst verarbeitet (z.B. Druckjobs). Stacks sind sogenannte Kellerstapel,
die nach dem LIFO-Prinzip (last in, first out) funktionieren. Das bedeutet,
das zuletzt eingef¨
ugte Element wird zuerst verarbeitet.
Assoziative Container: sind z.B. Maps (Karten) und Bitsets. Die Elemente sind nicht wie bei sequentiellen Container linear angeordnet sondern
in bestimmtem Strukturen (z.B. Baumstrukturen). Dies erm¨oglicht einen
besonders schnellen Datenzugriff, der u
usselung erfolgt.
¨ ber eine Verschl¨
63
64
KAPITEL 8 CONTAINER
Container
sequential
Container
Vectors
Stacks
associative
Container
Queues
Sets
Maps
Bitsets
Abbildung 8.1: C++ Container (Bildquellen: www.prachensky.com)
Die Besonderheit der C++ Container ist die dynamische Speicherverwaltung.
Das heisst, Einf¨
ugen und Entfernen von Container-Elementen ist sehr einfach,
wir brauchen uns nicht selbst um das Speichermanagement zu k¨
ummern. Dies
u
¨ bernehmen die Konstruktoren und Destruktoren (siehe Abschnitt 4.4) der jeweiligen Container-Klasse.
8.1
Sequentielle Container
Ein weiterer Grund f¨
ur die Bereitstellung von Containern ist, dass die Elemente
gemeinsame Datentypen und Methoden haben. Der Datentyp T eines Containers
ist nat¨
urlich eine (beliebige) Klasse. Die Tab. 8.1 listet die Klassentemplates f¨
ur
einige sequentielle Container sowie die ben¨otigen Include-Files auf.
Ein Klassentemplate ist nichts weiter als eine formale Beschreibung der Syntax.
8.2 VECTORS
65
Klassen-Template
vector<T,Allocator>
list<T,Allocator>
stack<T,Container>
queue<T,Container>
Include-Files
<vector>
<list>
<stack>
<queue>
Tabelle 8.1: Klassentemplates f¨
ur sequentielle Container
• vector: Schl¨
usselwort
• < ... >: Parameterliste
• T: erster Parameter, Datentyp des Vektors
• Allocator: zweiter Parameter, Speichermodell des Vektors
Die Methoden sequentieller Container sind sehr einfach, intuitiv zu bedienen
und sie sind gleich f¨
ur Vektoren, Listen etc. Ein Auswahl der wichtigsten gemeinsamen Methoden finden sie in der nachfolgenden Tabelle.
Methode
size()
push back(T)
pop back()
insert(p,T)
erase(p)
clear()
resize(n)
Bedeutung
Anzahl der Elemente, L¨ange de Containers
Einf¨
ugen eines Elements am Ende
L¨
oschen des letzten Elements
Einf¨
ugen eines Elements vor p
L¨
oschen des p-Elements (an der Stelle p)
L¨
oscht alle Elemente
¨
Andern
der Containerl¨ange
Tabelle 8.2: Methoden f¨
ur sequentielle Container
8.2
Vectors
The standard vector is a template defined in namespace std and presented in
<vector>. The vector container is introduced in stages: member types, iterators,
element access, constructors, list operations etc. The structure of a vector is
illustrated in Fig. 8.2.
Abbildung 8.2: Structure of vectors
Following lines are necessary in order to use the vector container in your sources
code.
66
KAPITEL 8 CONTAINER
#include <vector>
using namespace std;
Types: Very different types can be used in vectors. A vector e.g. of integers can
be declared in this way.
// Declaration and construction
vector<int> v;
Constructors: With the above source code a vector of integer types is constructed
as well.
Stack operators: The functions push back and pop back treat the vector as a
stack by adding and removing elements from its end.
// Input elements to vector
for(i=0;i<9;i++)
{
v.push_back(i+1);
}
Iterators: Iterators can be used to navigate containers without the programmer
having to know the actual type to identify the elements, e.g. for inserting and
deleting elements. A few number of key functions allow to step through the
elements, such as begin() pointing to first element and end() pointing to the
one-past-last element. An example of a loop through all vector elements using
the iterator is given below.
// Navigating vector elements
for(vector<int>::iterator it=v.begin(); it!=v.end(); ++it)
{
cout << *it << ’\n’;
}
Vector elements can be addressed directly by element number. Fast data access
is an advantage of vectors.
Abbildung 8.3: Access to vector elements
In contrast, vectors are not as flexible as lists. Deleting and adding of elements
within the vector is complicated (Fig. 8.4).
8.2 VECTORS
67
Abbildung 8.4: Deleting elements
Programming exercises
8.2.1
Defining vectors
In the first exercise we just define a vector and insert some elements into it in
order to show the concept.
Exercise 8.2.1
#include <iostream>
// for using cout
#include <vector>
// for using vectors
using namespace std; // for std functions
void main()
{
//------------------------------------------------------cout << "E81 - Working with vectors" << endl;
//------------------------------------------------------vector<int>my_vector;
// Declaration of vector
my_vector.push_back(1); // Inserting an element to vector
my_vector.push_back(3);
my_vector.push_back(5);
for(int i=0;i<(int)my_vector.size();i++)
{
cout << my_vector[i] << endl; // Access to vector elements
}
//------------------------------------------------------}
8.2.2
Vectors and data base
¨
In der n¨
achsten Ubung
werden einige Dinge, die wir bisher gelernt haben, zusammenbringen. Sie werden sehen, dass ’gut’ programmierte Dinge einfach ’zusammengebaut’ werden k¨
onnen: Objekte (Kapitel 4), IO-Methoden (Kapitel 6),
Stringverarbeitung (Kapitel 5).
68
KAPITEL 8 CONTAINER
Exercise 8.2.2
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include "student.h"
using namespace std;
//
//
//
//
//
//
for
for
for
for
for
for
using cout
using ifstream / ofstream
using string
using vectors
using CStudents
std functions
#define MAX_ZEILE 256
bool STDRead(ifstream&);
int main()
{
//---------------------------------------------------------------cout << "E82: an object-oriented DB read function" << endl;
//---------------------------------------------------------------// 1 File handling
ifstream input_file; // ifstream instance
input_file.open("data_base.txt");
if(!input_file.good())
// Check is file existing
{
cout << "! Error: input file could not be opened" << endl;
return 0;
}
//---------------------------------------------------------------// 2 Read data base
STDRead(input_file);
//---------------------------------------------------------------return 0;
}
Unser Programm besteht aus drei gekapselten Teilen:
• main(): Das Hauptprogramm: die Steuerzentrale, hier wir i.W. das Dateimanagement erledigt.
• STDRead(ifstream&): Die u
ur die komplet¨ bergeordnete Lesefunktion f¨
te Datenbank, hier befindet sich eigentlich nur eine Schleife, welche die
Objekt-Lesefunktion aufruft, solange Daten in der Datei vorhanden sind.
• CStudent::Read(ifstream): Die Objekt-Lesefunktion, die liest die eigentlichen Daten f¨
ur jeden Datensatz aus der Datenbankdatei.
¨
Der einzige Ubergabeparameter
ist die Datenbank-Datei: std file.
8.2 VECTORS
69
Exercise 8.2.2 continued
/**************************************************************************
STDLib-Method:
Task: Reading all STD objects
06/2009 OK Implementation
**************************************************************************/
bool STDRead(ifstream& std_file)
{
//-1-------------------------------------------------------------------char line[MAX_ZEILE];
string line_string;
ios::pos_type position;
vector<CStudent*>std_vector;
CStudent* m_std = NULL;
//---------------------------------------------------------------------//OK STDDelete();
//-2-------------------------------------------------------------------// rewind the file
std_file.seekg(0,ios::beg);
//-3-------------------------------------------------------------------// OBJ reading, keyword loop
cout << "STDRead" << endl;
while (!std_file.eof())
{
std_file.getline(line,MAX_ZEILE);
line_string = line;
if(line_string.find("#STOP")!=string::npos)
break;
if(line_string.find("#STUDENT")!=string::npos)
{
m_std = new CStudent();
position = m_std->Read(std_file); // from E63
std_vector.push_back(m_std);
std_file.seekg(position,ios::beg);
}
} // eof
//---------------------------------------------------------------------cout << "Number of data sets: " << std_vector.size() << endl;
return true;
}
8.2.3
Updating your data base entry
Homework 8.2.3a: Please update your data base entries and send it by mail to
me ([email protected]).
Homework 8.2.3b: Please write a print function for the CStudent class.
70
8.3
KAPITEL 8 CONTAINER
Lists
A list is a sequence optimized for insertion and deletion of elements. They allow
a very flexible organization of elements. But the price for flexibility is a relatively
slow access to data.
List provides bidirectional iterators (Fig. 8.3). This implies that a STL list will
typically be implemented using some form of a doubly-linked list.
Abbildung 8.5: Structure of lists
Following lines are necessary in order to use the list container in your sources
code.
#include <list>
using namespace std;
Types: All data types are possible for lists, e.g. a class.
// Declaration
list<CStudent*> std_list;
list<int> int_list;
Constructors: With the above source code a list for class instances is constructed
as well.
Stack operators: Lists provide same typical member functions as for vectors.
// Insert list elements at end
CStudent* m_std;
my_list.push_back(m_std);
Iterators: Again iterators can be used to navigate lists. We show an example for
deleting a specific element from the list. Identification of the list element is by
name (Fig. 8.6).
Abbildung 8.6: Deleting list elements
The following exercise shows how conveniently we can deal with lists, i.e. in
order to sort, reverse, merge, and unify lists. The unifying function removes
8.3 LISTS
71
multiple entries from lists, which is a very nice tool in order to clean a data
base.
Exercise 8.3
#include <iostream> // for using cout
#include <list>
// for using lists
using namespace std; // for std functions
typedef list<int>INTLIST;
void display(list<int>);
int main()
{
int i;
list<int>list1;
INTLIST list2;
// Filling the list with random numbers
for(i=0;i<4;i++)
{
list1.push_back(rand()%10);
list2.push_back(rand()%10);
}
display(list1); // Display the list
display(list2);
// Putting first element to the end as well
list1.push_back(list1.front());
list1.reverse();
// Reverse list
list1.sort();
// Sort list
list1.merge(list2); // Merge two lists
list1.sort();
// Remove multiple entries #1
list1.unique();
// Remove multiple entries #2
return 0;
}
void display(list<int>my_list)
{
int i;
list<int>::const_iterator iterator;
iterator = my_list.begin();
while(iterator != my_list.end())
{
i = *iterator;
cout << i << endl;
++iterator;
}
}
The concept of the data base read function is illustrated in Fig. 8.7.
72
KAPITEL 8 CONTAINER
main()
Files
STDRead(ifstream&)
STD::Read()
Abbildung 8.7: Data base read concept
The last exercise shows how we can delete entries from the students data base
(i.e. people we don’t like)
// Deleting list elements
CStudent* m_std = NULL;
list<CStudent*>::const_iterator p = std_list.begin();
while(p!=std_list.end())
{
m_std = *p;
if(m_std->GetStudentName()=="James Bond")
{
my_list.remove(*p);
break;
}
++p;
}
// Deleting repeated entries
std_list.unique();
8.4
Testfragen
1. Was sind C++ Container ?
2. Welche Typen von C++ Containern kennen sie ?
3. Worin besteht der Unterschied zwischen sequentiellen und assoziativen
Containern ?
4. Welche sequentiellen Container kennen sie ?
5. Erkl¨
aren sie die Syntax des Vektor-Containers: vector<int>my vector .
6. Was ist der Unterschied zwischen Vektoren und Listen ?
7. Was sind die Gemeinsamkeiten von Vektoren und Listen ?
8. Welcher Include ist notwendig f¨
ur das Arbeiten mit Vektoren ?
9. Welcher Include ist notwendig f¨
ur das Arbeiten mit Listen ?
8.4 TESTFRAGEN
73
10. Ben¨
otigen wir den Zusatz (Namensraum) using namespace std, wenn ja
warum ?
11. Mit welcher Instruktion k¨
onnen Elemente in Vektoren und Listen einf¨
ugen
?
12. Wo werden sequentielle Container-Elemente mit der Instruktion
ugt ?
push back(T) eingef¨
13. Mit welcher Anweisung k¨
onnen wir die L¨ange von sequentiellen ContainerElementen bestimmen ?
14. Mit welcher Anweisung k¨
onnen wir einen Vektor platt machen (d.h. alle
Elemente l¨
oschen) ?
15. Wie k¨
onnen wir auf ein Vektor-Element, sagen wir das 17te Element des
Vektors vector<int>my vector, direkt zugreifen ?
16. Quellcode verstehen: Erkl¨
aren sie die Struktur (1,2,3) der DB-Lese-Funktion
¨
8.2.2. Beginnen sie mit der PaSTDRead(ifstream& std file) in der Ubung
rameterliste.
17. Wie k¨
onnen wir unsere Studenten-Klasse CStudent in die DB-Anwendung
¨
(Ubung
8.2.1) einbinden ?
¨
18. Was ist eigentliche Lesefunktion f¨
ur unsere Studenten-Datens¨atze (Ubung
8.2.2) ?
19. Mit welchem Befehl k¨
onnen wir die Reihenfolge von Listen-Elementen
umkehren ?
20. K¨
onnen wir Listen-Elemente sortieren, wenn ja wie, mit welcher Instruktion ?
21. Mit welchem Befehl k¨
onnen wir mehrere Listen zusammenf¨
uhren ?
22. K¨
onnen wir doppelte Elemente aus einer Liste entfernen sortieren, wenn
ja wie, mit welcher Instruktion ?
23. Was ist ein Iterator ?
24. Quellcode verstehen: Erkl¨
aren sie die Funktion
¨
8.3. Beginnen sie mit der
void display(list<int>my list) der Ubung
Parameterliste.
25. Wie k¨
onnen wir Elemente aus einer Liste entfernen ?
Kapitel 9
Andere Sprachelemente
Wir haben das Ende der C++ Grundvorlesung erreicht (hoffentlich ein Grund
zur Freude). Das Ziel der Vorlesung ’Hydroinformatik’ ist allerdings bei Weitem
noch nicht erreicht. Sie erinnern sich, wir wollen eine Dialog-gef¨
uhrte DatenbankAnwendung (Fig. 4) mit C++ entwickeln. Sie werden sehen, dass wir fast alle Bausteine beisammen haben (außer die Grafik-Programmierung mit Visual
C++) und die Realisierung unser Applikation (nach der langen Vorbereitung)
dann sehr schnell geht.
Bevor wir zum graphischen (Visual) C++ kommen, wollen wir Sprachelemente (C++ news), die wir zuvor schon benutzt haben, aber noch nicht explizit
besprochen haben, hier kurz einf¨
uhren.
9.1
Kontrollstrukturen
Bei Kontrollstrukturen handelt es sich um Sprachelemente f¨
ur bedingte Anweisungen und Schleifen mit Z¨ahlern und Bedingungen.
Control
if-else
switch-case
for
while
Bedeutung
Anweisungen mit Bedingungen
Fallunterscheidungen
Schleifen mit Z¨ahlern
Schleifen mit Bedingungen
Tabelle 9.1: Kontrollstrukturen
Verschachtelungen von Kontrollstrukturen sind nat¨
urlich m¨oglich.
74
9.1 KONTROLLSTRUKTUREN
9.1.1
75
if-else
Es geht um die Ausf¨
uhrung von Anweisungen und Alternativen unter bestimmten Bedingungen. Ausf¨
uhrung einer Anweisung unter einer Bedingung (siehe,
¨
z.B. Ubung
8.2.2):
if(logische Bedingung)
{...} // Ausf¨
uhrung, wenn Bedingung erf¨
ullt ist
Ausf¨
uhrung einer Anweisung unter einer Bedingung mit Alternative (else) (sie¨
he, z.B. Ubung
8.2.2):
if(logische Bedingung)
{...} // Ausf¨
uhrung, wenn Bedingung erf¨
ullt ist
else
{...} // Ausf¨
uhrung, wenn Bedingung nicht erf¨
ullt ist
9.1.2
switch-case
Die Kontrollstruktur switch-case bietet die M¨oglichkeit von Fallunterscheidungen durch Ausdr¨
ucke (z.B. Aufz¨
ahlungen durch Zahlen). Der Schalter switch
springt entsprechend dem Zahlenausdruck in einen Fall case.
switch(Ausdruck)
{
case 0: // wenn Ausdruck == 0
... // Anweisungen
break; // Verlassen
default: // wenn kein Ausdruck zutrifft
}
Es gibt eine weitere Variante, wo der Ausdruck ein Zeichen sein kann.
switch(Ausdruck)
{
case ’A’: // wenn Ausdruck == A
... // Anweisung
break; // Verlassen
}
Eine weitere M¨
oglichkeit diese Kontrollstruktur elegant einzusetzen ist die Benutzung von enum - einem Konstrukt f¨
ur eigene Z¨ahler.
enum Wochentag {Montag,Dienstag,Mittwoch,Donnerstag,Freitag,Samstag,Sonntag}
Die einzelnen Wochentage bekommen dann aufsteigende Werte (von 0 beginnend) zugewiesen. Dann k¨
onnen wir unsere Fallunterscheidung (z.B. f¨
ur das
Mensa-Men¨
u) wie folgt schreiben:
76
KAPITEL 9 ANDERE SPRACHELEMENTE
switch(Wochentag)
{
case Montag:
// wenn Wochentag == 0
case Dienstag: // wenn Wochentag == 1
...
case Sonntag: // wenn Wochentag == 6
}
9.1.3
for
Die for Schleife ist eine Schleife mit einem Z¨ahler.
for(int i=0;i<stop;i++)
{
... // Anweisungen
}
Die Anweisungen im Funktionsrumpf {...} werden solange ausgef¨
uhrt, bis der
Z¨
ahler den Wert stop erreicht (das heißt, f¨
ur den Wert stop wird die Schleife
nicht mehr ausgef¨
uhrt). Bei jedem Schleifendurchlauf wird der Z¨ahler i um Eins
(i++) hochgez¨
ahlt. Ich habe gerade mal nachgesehen. In unserem Programmsystem OpenGeoSys wird die for-Schleife u
¨ ber 4000 mal verwendet! Wir haben
¨
sie z.B. in der Ubung
8.2.1 zum Generieren von Vektor-Elementen benutzt.
9.1.4
while
Die while Schleife ist eine Endlos-Schleife mit einer Bedingung.
while(Bedingung)
{
... // Anweisungen
}
Die Anweisungen im Funktionsrumpf {...} werden ausgef¨
uhrt, solange die Bedingung erf¨
ullt (das heißt, der numerische Wert Bedingung muss gr¨oßer als 0
sein). Um aus der Schleife herauszukommen, muss also der Wert der Bedingung
ge¨
andert werden - oder ’hart’ abgebrochen werden (siehe n¨achster Abschn. 9.1.5)
In unserem Programmsystem OpenGeoSys wird die while-Schleife fast 500 mal
¨
verwendet! Wir haben sie f¨
ur unsere Lesefunktion (Ubung
8.2.1) und beim Ite¨
rieren in Listen (Ubung
8.2.1) verwendet.
9.1.5
continue, break, return
Es gibt mehrere M¨
oglichkeiten, um Kontrollstrukturen (vorzeitig) verlassen zu
k¨
onnen.
¨
9.2 GULTIGKEITSBEREICHE
9.2
77
Gu
¨ltigkeitsbereiche
F¨
ur alles, was wir deklarieren, Funktionen, Klassen, Variablen gibt es G¨
ultigkeitsbereiche. Wenn irgendwo etwas definieren, ist es also nicht u
¨ berall sichtbar. Wir hatten uns mit diesem Thema schon bei der Definition von ’privaten’
Klassen-Elementen besch¨
aftigt (Abschn. 4.6). Die Abb. ?? zeigt das Prinzip von
lokalen und globalen G¨
ultigkeitsbereichen. Wir sollen immer versuchen soviel
wie m¨
oglich lokal zu definieren, das unterst¨
utzt die Daten-Kapselung in unserem Programm. Klassen sind immer nur dort sichtbar, wo ihre Header-Dateien
inkludiert worden sind.
9.2.1
Namensbereiche
Sind uns auch schon mehrfach begegnet bei der Verwendung von Strings, Vektoren und Listen. Dabei wurde nach dem Includieren der entsprechenden HeaderDateien die Anweisung using namespace std benutzt. Strings, Vektoren und
Listen geh¨
oren zum Namensraum der Standard-Bibliothek STL.
#include <strings>
std::my_string("Beispiel ohne Namensbereich");
using namespace std;
my_string("Beispiel mit Namensbereich");
Wir k¨
onnen auch eigene Namensbereiche definieren.
namespace Meins
{ // hier sind Funktionen des Namensbereichs
class CStudent
}
using namespace Meins;
Wozu ? Wenn sie ihren Programmcode mit einem anderen Entwickler zusammenf¨
uhren wollen und es gibt mehrere Klassen CStudent, dann k¨onnen sie sicher
auf ihre Funktion zugreifen, wenn sie ihren Namensraum gesetzt haben.
9.2.2
Compiler-Direktiven – #
Alles was mit # anf¨
angt, versetzt den Kompiler in den Alarmzustand - es sind
sogenannte Kompiler-Direktiven, das heißt beim Kompilieren werden gewisse
Weichen gestellt.
78
KAPITEL 9 ANDERE SPRACHELEMENTE
Direktive
#include
#define
#ifdef
#ifndef
#endif
#define
Wirkung
Einf¨
ugen einer Header-Datei
Definition einer Direktive
Wenn die Direktive gilt
Wenn sie nicht gilt
Ende der Direktive
Definition eines Makros
Tabelle 9.2: Compiler-Direktiven
9.2.2.1
Includes
Ohne Includes geht gar nichts, sie erinnern sich, selbst um einfache Bildschirmausgaben mit cout machen zu k¨onnen mussten wir Klasse iostream einf¨
ugen.
An dieser Stelle nochmal zur Erinnerung. Es gibt Arten von Includes:
<Header> Die eckigen Klammern bedeuten, es geht um einen System-Inklude.
Es wird im Systemverzeichnis (dort wo C++ installiert ist) gesucht.
”Header” Die G¨
ansef¨
ußchen bedeuten, es geht um einen eigenen Inklude. Es
wird lokalem Verzeichnis gesucht.
Wenn der Programm-Code verzweigt ist, also eine komplexere Verzeichnisstruktur hat, m¨
ussen Pfade der Inklude-Dateien mit angegeben werden, sonst werden
sie nicht gefunden. Keine Angst, in diesem Falle bekommen sie sofort eine eindeutige Fehler-Meldung beim Versuch zu Kompilieren.
9.2.2.2
Bedingte Kompilation
Eine sehr n¨
utzliche Sache sind Direktiven f¨
ur die Kompilation von Test-Versionen.
Gerade w¨
ahrend der Entwicklung m¨ochte man neue Programmteile einfach anund ausschalten k¨
onnen. Dies geht mit der Kompiler-Direktive (KD) #ifdef.
#define TEST
#ifdef TEST
...
#endif
// Anschalten der Direktive TEST
Wenn die Kompiler-Direktive TEST an ist, wird der Programmtext von der Stelle #ifdef bis #endif beim Kompilieren u
¨ bersetzt, ansonsten einfach ignoriert.
Kompiler-Direktiven sind immer aus, wenn sie nicht explizit eingeschaltet werden. Das Gegenst¨
uck von #ifdef ist #infdef, also wenn die Kompiler-Direktive
aus ist. Oft m¨
ussen Funktionen u
¨berarbeitet werden. Mit Kompiler-Direktiven
kann man sehr sch¨
on eine neue Variante der Funktion entwickeln und die alte
9.3 TESTFRAGEN
79
erstmal zu Vergleichszwecken beibehalten. Erst wenn alles richtig funktioniert,
schmeißt man das alte Zeug weg.
¨
Ubung
9.2.2.2:
#define NEW_VERSION // Anschalten der Direktive NEW_VERSION
#ifdef NEW_VERSION
... // wenn NEW_VERSION an ist
#else
... // wenn NEW_VERSION aus ist
#endif
¨
Ich empfehle ihnen, das mal in irgendeiner Ubung
auszuprobieren. Wichtig:
Denken sie immer an das #endif zum Ausschalten, sonst gilt die KompilerDirektive bis zum Ende des gesamten Programms.
9.2.2.3
Makros
Die Kompiler-Direktive #define kann auch zur Definition sogenannter Makros
verwendet werden, z.B. f¨
ur Konstanten, die man oft benutzt. Es geht aber auch
f¨
ur einfache Funktionen oder sogar Print-Anweisungen.
#define PI 3.1416 // Definition der Zahl PI
#define MULT(a,b) ((a)*(b))
#define PRINT(x) cout << (#x) << ": " << (x);
Der Makro-Einsatz sollte aber nicht u
ur
¨ bertrieben werden, eigentlich gibt es daf¨
richtige Funktionen. Bei Makros werden z.B. keine Pr¨
ufungen durch den Kompiler gemacht, daher sind sie fehleranf¨allig.
9.3
Testfragen
1. Was sind Kontrollstrukturen, welche kennen sie ?
2. Bei welcher logischen Bedingung wird eine if-Anweisung ausgef¨
uhrt ?
3. Lassen sich Kontroll-Strukturen verschachteln ?
4. Mit welcher Kontrollstruktur k¨onnen wir Fallunterscheidungen programmieren ?
5. Welche Ausdr¨
ucke k¨
onnen wir bei der switch-case Kontrollstruktur benutzen ?
6. Wie kann ich eine Kompiler-Direktive an- und ausschalten ?
80
KAPITEL 9 ANDERE SPRACHELEMENTE
¨
7. Schreiben sie die Ubung
9.2.2.2 f¨
ur die Benutzung von #ifndef anstelle
von #ifdef um.
8. Erl¨
autern sie den Kopf der for-Schleife: for(int i=0;i<stop;i++), welchen Daten-Typ hat stop ?
9. Was ist eine Endlos-Schleife, wie kommen wir daraus ?
10. Was sind Namensbereiche ?
11. Was m¨
ussen wir tun, um die Arbeit mit C++ Standard-Klassen zu vereinfachen, d.h anstelle von std::my string() direkt my string() benutzen
zu k¨
onnen ?
12. Was sind Kompiler-Direktiven, was bewirken diese ?
13. Wie k¨
onnen wir Kompiler-Direktiven an- und ausschalten ?
14. Worin besteht der Unterschied bei Includes mit eckigen Klammern < ... >
bzw. mit G¨
ansef¨
ußchen ”...” ?
¨
15. Schreiben sie die Ubung
9.2.2.2 f¨
ur die Benutzung von #ifndef anstelle
von #ifdef um ?
16. Was sind Makros ?
17. Welche beiden Einsatzm¨oglickeiten von Makros gibt es ?
18. Worin besteht die Gefahr, Makros als Funktionsersatz zu benutzen ?
Part II
Visual C++
Kapitel 10
Qt
Die Geschichte: Bei der ersten HI-I Vorlesung gabe es ziemlich peinliche ei¨
ne Panne. Die (mit viel M¨
uhe vorbereiteten Ubungen)
liefen zwar mit meiner
MSVC++ (professional) Version aber (nicht ohne Weiteres) mit freien MSVC++
Express Version, wo die MFC standartm¨aßig nicht mehr dabei ist. Dies zeigt uns
aber, auch beim Programmieren niemals nur auf ein Pferd setzen. Wichtig ist,
unser eigener Code muss C++ Standard sein, den k¨onnen wir dann problemlos
in verschiedene GUI Frameworks, wie MSVC++, Qt etc. einbauen. Warum jetzt
¨
noch Qt ? Wir werden in den Ubungen
sehen, dass Qt sehr dicht an C++ Standards dran ist und Qt ist a cross-platform GUI. Qt l¨auft auf Windows, Linux,
Mac ... In der Anlage 5.1 finden sie eine Anleitung zur Installation von Qt.
10.1
Hello Qt
Wie es sich f¨
ur ein ordentliches Programmier-Framework geh¨ort, ist die erste
¨
Ubung
”Hello World” auf graphisch.
¨
Ubung:
10.1
#include <QApplication>
#include <QLabel>
int main(int argc, char *argv[])
{
QApplication app(argc,argv);
QLabel *label = new QLabel("Hello Qt!");
label->show();
return app.exec();
}
82
10.2 EXECUTABLE VON DER KONSOLE STARTEN
83
Sehr erfreulich ist die N¨
ahe von Qt zum Standard C++, es gibt eine klassische
main() Funktion. Die Komposition von ”Hello Qt” ist sehr einfach:
• Es wird eine Qt Application angelegt (¨ahnlich wie bei Windows, aber doch
irgendwie einfacher),
• Es wird ein Label angelegt, das mit der Methode →show() angezeigt wird.
Qt bietet auch die M¨
oglichkeit, einfach HTML code zu integrieren. Ersetzen sie
die QLabel Zeile wie folgt.
QLabel *label = new QLabel("<h2><i>Hello<!i>""<font color=red>Qt!</font></h2>");
Abbildung 10.1: Hallo Qt
10.2
Executable von der Konsole starten
Um ein ausf¨
uhrbares Qt Programm zu erzeugen ben¨otigen wir 3+1 Schritte:
• Gehen sie in ihre Start - Programme Men¨
u (Windows) und starten sie die
den Qt command prompt (Fig. 10.2).
Abbildung 10.2: Qt Kommando Zeile
• Mit qmake -project erzeugen sie ein Qt Projekt.
• Mit qmake legen sie ein makefile an.
• Mit mingw32-make (kein Leerzeichen) kompilieren sie das Projekt und
generieren ein ausf¨
uhrbares Programm.
• Mit E10 1 HelloQt.exe starten sie das Programm.
84
KAPITEL 10 QT
.
Abbildung 10.3: Die Schritte in Bildern ...
10.3
Quit - Schaltfl¨
achen
¨
Die n¨
achste Ubung
zeigt uns, wie einfach mit Schalt߬achen (Push Button) gearbeitet werden kann.
#include <QApplication>
#include <QPushButton>
int main(int argc, char *argv[])
{
QApplication app(argc,argv);
QPushButton *button = new QPushButton("Quit");
QObject::connect(button, SIGNAL(clicked()),&app, SLOT(quit()));
button->show();
return app.exec();
}
Im Unterschied zu ”Hello Qt” ist eine Kommunikation mit dem Anwender
(dr¨
ucken der Schalt߬
ache) notwendig. Die Signalverarbeitung erfolgt u
¨ ber die
Object-Methode connect.
QObject::connect(button, SIGNAL(clicked()),&app, SLOT(quit()));
10.4 DIALOGE
85
Dabei wird die Nachricht SIGNAL(clicked()) mit der Schalt߬ache Quit mit
einem sogenannten SLOT(quit())) verbunden.
Abbildung 10.4: Hallo Qt
10.4
Dialoge
Zum Abschluss unsere Dialog-Anwendung. Dabei wird in der main Funktion
eine Instanz der Klasse QDialog erzeugt.
#include <QtGui/QApplication>
#include "dialog.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Dialog w;
w.show();
return a.exec();
}
Der Header des Dialogs enth¨
alt im Wesentlichen die Resourcen-Elemente, z.B.
die Schalt߬
ache pushButtonReadDB zum Lesen der Datenbank sowie die dazugeh¨
origen Funktionen on pushButtonReadDB clicked().
class Dialog : public QDialog
{
Q_OBJECT
public:
Dialog(QWidget *parent = 0);
~Dialog();
private:
Ui::Dialog *ui;
QListWidget
QPushButton
QPushButton
QPushButton
*listWidget;
*pushButtonReadDB;
*pushButtonAdd;
*pushButtonDelete;
86
KAPITEL 10 QT
QLineEdit *lineEditNameFirst;
QLineEdit *lineEditNameLast;
private slots:
void on_pushButtonReadDB_clicked();
void on_pushButtonAdd_clicked();
void on_pushButtonDelete_clicked();
void on_listWidget_clicked();
};
Die Implementierung des Dialogs besteht aus drei Teilen:
1. Konstruktion der grafischen Resourcen-Elemente: pushButton (Schaltfl¨achen),
listWidget (Liste), lineEdit (Editierfelder),
2. Signalverarbeitung: Wenn pushButtonReadDB gedr¨
uckt wurde, f¨
uhre die
Funktion on pushButtonReadDB clicked aus,
3. Layout: Es werden horizontale und vertikale Boxen angelegt.
Dialog::Dialog(QWidget *parent)
: QDialog(parent), ui(new Ui::Dialog)
{
ui->setupUi(this);
// 1.1 - pushButton
pushButtonReadDB = new QPushButton(tr("&Read DB"));
pushButtonAdd = new QPushButton(tr("&Add DS"));
pushButtonDelete = new QPushButton(tr("&Delete DS"));
// 1.2 - listWidget
QString name = "Tom Hanks";
QStringList names;
names << name << "Alice Wunderland" << "Bob Dylan" << "Carol Crow"
<< "Donald Dug" << "Emma Thomson";
listWidget = new QListWidget();
for (int row = 0; row < 5; ++row) {
listWidget->addItem(names[row]);
}
//1.3 - lineEdit
lineEditNameFirst = new QLineEdit();
lineEditNameFirst->insert("Tom");
lineEditNameLast = new QLineEdit();
lineEditNameLast->insert("Hanks");
// 2 - connect
connect(pushButtonReadDB,SIGNAL(clicked()),this,
SLOT(on_pushButtonReadDB_clicked()));
connect(pushButtonAdd,SIGNAL(clicked()),this,
SLOT(on_pushButtonAdd_clicked()));
connect(pushButtonDelete,SIGNAL(clicked()),this,
10.4 DIALOGE
87
SLOT(on_pushButtonDelete_clicked()));
connect(listWidget,SIGNAL(itemSelectionChanged()),this,
SLOT(on_listWidget_clicked()));
//3 - Layout
QHBoxLayout *leftTopLayout = new QHBoxLayout;
leftTopLayout->addWidget(lineEditNameFirst);
leftTopLayout->addWidget(lineEditNameLast);
QVBoxLayout *leftLayout = new QVBoxLayout;
leftLayout->addLayout(leftTopLayout);
leftLayout->addWidget(listWidget);
QVBoxLayout *rightLayout = new QVBoxLayout;
rightLayout->addWidget(pushButton);
rightLayout->addWidget(pushButtonAdd);
rightLayout->addWidget(pushButtonDelete);
rightLayout->addStretch();
QHBoxLayout *mainLayout = new QHBoxLayout;
mainLayout->addLayout(leftLayout);
mainLayout->addLayout(rightLayout);
setLayout(mainLayout);
}
Das Ergebnis der Dialog-Implementierung sehen wir in Abb. 10.5.
Abbildung 10.5: Qt Dialog
Um zu pr¨
ufen, ob die Signalverarbeitung hinter den Kn¨opfchen funktioniert,
rufen wir eine MessageBox auf.
void Dialog::on_pushButtonAdd_clicked()
{
QMessageBox msgBox;
msgBox.setText("pushButtonAdd clicked");
88
KAPITEL 10 QT
msgBox.exec();
}
10.5 QT PROJEKT
10.5
89
Qt Projekt
Es ist ihnen hoffentlich gelungen, Qt f¨
ur ihr Betriebssystem erfolgreich zu installieren. Eine kurze Installationsanleitung war im Skript [?] (Abschn. 12.8) zu
finden. Hier noch mal die Web-Seite f¨
ur den Download
http://qt.nokia.com/products. Der große Vorteil von Qt ist die Plattformunabh¨angigkeit sowie die freie Verf¨
ugbarkeit unter der GPL (Gnu Public License).
Wir starten Qt mit einem Doppelklick auf das Desktop-Symbol (Abb. 11.4).
Abbildung 10.6: Qt Start
Wenn alles gut geht gegangen ist sollten sie im Qt User Interface (UI) landen
(Abb. 11.4).
Abbildung 10.7: Qt Creator
Zun¨achst m¨
ussen wir ein neues (leeres) Qt Projekt anlegen (Abb. 11.4-10.11).
Abbildung 10.8: Neues Qt Projekt anlegen - Schritt 1
Schritte:
• pro Datei
90
KAPITEL 10 QT
.
Abbildung 10.9: Neues Qt Projekt anlegen - Schritt 2
Abbildung 10.10: Neues Qt Projekt anlegen - Schritt 3
Abbildung 10.11: Neues Qt Projekt anlegen - Schritt 4
10.5 QT PROJEKT
91
Nachdem ein leeres Qt Projekt angelegt ist, f¨
ugen wir zun¨achst eine existierende
Quell-Datei mit der main Funktion hinzu (Abb. 10.12).
Abbildung 10.12: Hinzuf¨
ugen einer Quell-Datei
Es k¨
onnen weitere Quell-Dateien hinzugef¨
ugt werden, wie z.B. der Qt Plotter
(Abb. 10.13).
Abbildung 10.13: Qt Editor
92
KAPITEL 10 QT
Unser Projekt ist schon kompilierf¨ahig. Mit einem Druck auf das ”gr¨
une Kn¨opfchen” (Abb. 10.14) wird kompliert und das Programm ausgef¨
uhrt.
Abbildung 10.14: Kompilation und Programmstart
Im Ergebnis haben wir unseren ersten Qt Plot (Abb. 10.15), unheimlich - nicht
wahr.
Abbildung 10.15: Qt Plotter
Jetzt schauen wir uns die Sache mal etwas genauer an.
¨
Ubung:
E10.5
#include <QApplication>
#include "plotter.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
// Data
int numPoints = 100;
QVector<QPointF> points0;
QVector<QPointF> points1;
for (int x = 0; x < numPoints; ++x) {
points0.append(QPointF(x, uint(qrand()) % 100));
points1.append(QPointF(x, uint(qrand()) % 100));
10.5 QT PROJEKT
93
}
// Plotter
Plotter plotter;
plotter.setWindowTitle(QObject::tr("Jambi Plotter"));
plotter.setCurveData(0, points0);
plotter.setCurveData(1, points1);
PlotSettings settings;
settings.minX = 0.0;
settings.maxX = 100.0;
settings.minY = 0.0;
settings.maxY = 100.0;
plotter.setPlotSettings(settings);
plotter.show();
//
return app.exec();
}
Dies soll als kurze Einf¨
uhrung in Qt erstmal gen¨
ugen, es geht weiter im n¨achsten
Semester.
Part III
Anlagen / Software
Kapitel 11
Software-Installation
95
96
11.1
KAPITEL 11 SOFTWARE-INSTALLATION
Glossar
Compiler ist ein Programm (z.B. g++), das eine Quelldatei in Maschinencode
u
¨bersetzt.
Quelldatei ist ein File (z.B. main.cpp), das Quellcode enth¨alt.
Quellcode sind s¨
amtliche C++ Anweisungen.
Maschinencode ist ein ausf¨
uhrbares Program, z.B. a.exe.
11.2 CYGWIN INSTALLATION
11.2
97
cygwin Installation
In dieser Anlage finden sie eine Anleitung zur Installation von cygwin - dies ist
eine Linux-Umgebung f¨
ur Windows. In dieser Umgebung k¨onnen sie die GNU
C und C++ Compiler verwenden.
Abbildung 11.1: Schritt 1: Gehen sie auf cygwin Web Seite - www.cygwin.com.
Klicken sie auf das cygwin Symbol (Install or update now!).
Abbildung 11.2: Schritt 2: Laden sie die setup.exe Datei auf ihren Rechner
herunter und f¨
uhren sie die setup.exe aus.
98
KAPITEL 11 SOFTWARE-INSTALLATION
.
Abbildung 11.3: Schritt 3: Das cygwin setup Programm wird gestartet. Hier sehen sie auch die aktuelle Versionsnummer (2.573.2.3). Best¨atigen sie mit Weiter.
Abbildung 11.4: Schritt 4: W¨ahlen sie das Verzeichnis zur Installation von
cygwin aus, z.B. das Verzeichnis, in dem die Anwendungsprogramme sind
(C:/Programme). Behalten sie die Voreinstellungen. Best¨atigen sie mit Weiter.
11.2 CYGWIN INSTALLATION
99
.
Abbildung 11.5: Schritt 5: cygwin ben¨otigt ein tempor¨ares Verzeichnis f¨
ur die
Installation, das sp¨
ater gel¨
oscht werden kann. Behalten sie die Voreinstellungen.
Best¨
atigen sie mit Weiter.
Abbildung 11.6: Schritt 6: Benutzen sie die voreingestellte direkte Internetverbindung. Best¨
atigen sie mit Weiter.
100
KAPITEL 11 SOFTWARE-INSTALLATION
.
Abbildung 11.7: Schritt 7: W¨ahlen sie die download site, am besten die Dresdner:
http://ftp.inf.tu-dresden.de; Best¨atigen sie mit Weiter.
Liste der 6 zu installierenden Pakete aus der Kategorie ’Devel’:
• binutils: The GNU assembler linker and binary utilities (release 200806242) [6MB]
• gcc-core: C compiler (release 3.4.4.999) [3.6MB]
• gcc-g++: C++ compiler (release 3.4.4.999) [7.8MB]
• gcc-mingw-core: support headers and libraries for GCC (release 200505221) [69kB]
• gcc-mingw-g++: support headers and libraries for GCC C++ (release
20050522-1) [1.9MB]
• mingw-runtime library (release 3.15.2-1) [372kB]
11.2 CYGWIN INSTALLATION
101
.
Abbildung 11.8: Schritt 8: Nun erscheint die Liste der packages, die installiert
¨
werden k¨
onnen. Offnen
sie dem Baum Devel (klicken Sie auf das Plus-Symbol).
W¨
ahlen sie die oben aufgef¨
uhrten Pakete aus, welche f¨
ur die Installation von C
und C++ ben¨
otigt werden. Best¨
atigen sie mit Weiter.
Die nachfolgenden Abbildungen zeigen ihnen, welche Markierungen aktiviert
sein m¨
ussen, um den C (GCC) und den C++ (G++) zu installieren. Eigentlich
reicht es, die binutils, gcc-core und gcc-g++ auszuw¨ahlen, die restlichen
Pakete (mingw) m¨
ussten automatisch aktiviert werden. Egal, u
ufen sie, ob
¨ berpr¨
alles wie in den nachfolgenden Abbildungen markiert ist. Viel Erfolg!
102
KAPITEL 11 SOFTWARE-INSTALLATION
.
Abbildung 11.9: Schritt 8a: (aktive) Auswahl der binutils
Abbildung 11.10: Schritt 8b: (aktive) Auswahl der C und C++ Compiler
Die nachfolgenden Pakete sollte automatisch markiert werden, bitte u
ufen
¨ berpr¨
sie dies sicherheitshalber.
11.2 CYGWIN INSTALLATION
103
.
Abbildung 11.11: Schritt 8c: (automatische) Auswahl von Hilfspaketen
Abbildung 11.12: Schritt 8d: (automatische) Auswahl von Hilfspaketen
Abbildung 11.13: Schritt 9: Behalten sie die Voreinstellungen, um eine cygwin
Verkn¨
upfung auf ihrem desktop zu erstellen. Schließen sie die Installation ab.
104
KAPITEL 11 SOFTWARE-INSTALLATION
Im Ergebnis der Installation erhalten sie eine desktop Verkn¨
upfung mit cygwin,
das nun mit einem Doppelklick gestartet werden kann.
Abbildung 11.14: Schritt 8d: cygwin desktop Verkn¨
upfung
Starten sie cygwin mit einem Doppelclick auf die desktop Verkn¨
upfung.
Abbildung 11.15: Start von cygwin
Mit einem Rechtsklick auf den oberen Balken gelangen sie in das EigenschaftenMenu und k¨
onnen Einstellungen (z.B. Farben) nach ihrem Geschmack ¨andern.
11.2 CYGWIN INSTALLATION
105
.
Abbildung 11.16: Das Eigenschaften-Menu von cygwin
Testen sie, ob die Compiler einsetzbar sind, indem sie diese einfach aufrufen:
• gcc - Aufruf des C Compilers
• g++ - Aufruf des C++ Compilers
Da sie die Compiler ohne etwas zu tun aufrufen, erhalten sie die Meldung: keine
Eigabedateien.
Abbildung 11.17: Aufruf der Compiler
¨
Nun kann es also endlich losgehen mit der ersten Ubung
⇒ Abschnitt 1.4.
106
KAPITEL 11 SOFTWARE-INSTALLATION
11.3
LINUX
11.3.1
¨
Ubersicht
einiger grundlegenden Linux-Befehle
Befehl / command
Bedeutung
Hilfe
man
info
apropos
whatis
Klassische Hilfe (verlassen mit Q)
Online Hilfe von GNU (verlassen mit Q)
Schl¨
usselw¨
ortersuche bei man-Seiten
Kurzbeschreibung zu einem Kommando / Schl¨
usselwort
Dateien
ls
ls -attr
file
cp Quelle Ziel
mv Datei1 Datei2
mv Datei V1
rm Dateien
rmdir Verzeichnis
find
find/
Dateien auflisten
Dateiattribute auflisten
Dateityp ermitteln
Kopiert Quelle nach Ziel
Datei1 umbenennen in Datei2
Verschiebt Datei in das Verzeichnis V1
Dateien l¨
oschen
Verzeichnis l¨
oschen
Suche nach Dateien
Suche startet im Root-Verzeichnis / im ganzen System
Verzeichnisse
pwd
./
cd
mkdir
rm Verzeichnis
rmdir
ls
gibt aktuelles Arbeitsverzeichnis an
aktuelles Verzeichnis
Wechsel des aktuellen Verzeichnisses
ein Verzeichnis anlegen
ein Verzeichnis l¨
oschen
ein leeres Verzeichnis l¨
oschen
Verzeichnisinhalt auflisten
Systembefehle
shutdown -h
shutdown Uhrzeit
shutdown -t Sekunden
reboot oder
shutdown -r
uname
Herunterfahren des Systems
Herunterfahren des Systems bei Uhrzeit (z.B.: 14.00)
Herunterfahren des Systems nach Anzahl der Sekunden
Neustart des Systems
Systeminformationen ausgeben
¨
Diese Ubersicht
basiert auf ’Linux auf einem Blatt’ von Christian Helmbold
(www.helmbold.de) (siehe n¨achste Seite)
11.3 LINUX
107
weitere Informationen und Erkl¨
arungen
¨
deutsche Ubersichten:
¨
- Pdf-Ubersicht
’Linux auf einem Blatt’ (auch zum Download)
www.helmbold.de/linux
- Linux-Befehle f¨
ur Einsteiger
http://www.linux-fuer-alle.de/doc show.php?docid=33
¨
- Ubersicht
f¨
ur wichtige Linux-Befehle und Programme
http://www.tnt-computer.de/yanip/lbefehle.html
¨
englische Ubersichten
¨
- umfangreiche Ubersicht
mit Parametern und Beispielen
http://www.computerhope.com/unix.htm#04
- Vergleich zwischen MS-DOS- und Linux-Befehlen
http://www.yolinux.com/TUTORIALS/unix for dos users.html
Wir arbeiten uns jetzt mal mit der online-Hilfe ’man’ (steht f¨
ur Manual) weiter
vor.
Abbildung 11.18: Benutzen der online Hilfe
Mit dem Befehl man ls k¨
onnen wir uns die Optionen von ls (Dateien auflisten)
anzeigen lassen.
108
KAPITEL 11 SOFTWARE-INSTALLATION
.
Abbildung 11.19: Optionen von ls (Dateien auflisten)
11.3 LINUX
11.3.2
109
Profile
Wir n¨
ahern uns der L¨
osung, einfach in das Verzeichnis zu gelangen, in dem sich
¨
¨
unsere Ubungen
befinden. Ahnlich
wie in DOS die Programme autoexec.bat
und config.sys beim Start des Betriebsystems automatisch ausgef¨
uhrt werden,
ist es bei LINUX ein so genanntes Profile: .bash profile. In diese Datei k¨onnen
eigene Befehle eingetragen werden.
Eigentlich ist es ganz einfach ....
cd C:/User/TEACHING/C++/EXERCISES
Durch diese Instruktion in der .bash profile wechseln wir direkt in das Ver¨
zeichnis, in dem sich unsere Ubungen
befinden.
Nachdem wir verschiedene Editoren ausprobiert haben (und erhebliche Unterschiede in der Behandlung von Zeilenenden (CR) gesehen haben), ließ sich zu
¨
allem Ubel
unsere m¨
uhsam editierte .bash profile mit dem Windows-Explorer
nicht speichern (es liegt an dem Punkt am Anfang des Datei-Namens). Ich kann
ihre Entt¨
auschung gut verstehen, nicht umsonst gibt es Windows und LinuxAnh¨
anger. Dennoch m¨
ussen wir eine L¨osung finden oder ?
11.3.2.1
L¨
osung 1: unix2dos
Nach unserem Schiffbruch mit dem Speichern einer ’.bash profile’ unter Windows (’denkt’ vor dem Punkt kommt der Datei-Name und nach dem Punkt die
File-Extension, also nix vor dem Punkt heißt f¨
ur Windows, kein Datei-Name ...
so ist das, wenn Programme zu viel denken).
Die zweite L¨
osung ist eine Dateikonvertierung. Linux bietet zwei Programme an:
dos2unix und unix2dos, mit denen man Dateien plattformgerecht konvertieren
kann (Fig. 11.20)
Abbildung 11.20: Wandeln zwischen Linux und Dos-Dateien
110
11.3.2.2
KAPITEL 11 SOFTWARE-INSTALLATION
L¨
osung 2: Cygwin (the Linux point of view)
Wir brauchen einen ’einfachen’ Editor f¨
ur cygwin, d.h. wir m¨
ussen nachinstallieren (siehe Abschn. )
Abbildung 11.21: Nachinstallieren des vi Editors
Nach der vi Installation m¨
ussen wir in das Verzeichnis (home directory) gelangen, wo sich die .bash profile Datei befindet.
Abbildung 11.22: home directory und dessen Inhalt
11.3 LINUX
111
Wir ¨
offnen die .bash profile Datei mit dem vi Editor wie folgt:
Abbildung 11.23: Starten des vi Editors
Jetzt k¨
onnen wir mal einen Linux-Editor live erleben (danach werden sie Win¨
dows noch mehr ’lieben’ ...). Nach dem Offnen
der Datei gehen sie mit dem
Kursor dorthin, wo sie Text einf¨
ugen m¨ochten. Dann dr¨
ucken sie die ’i’ Taste,
der insert Modus wird gestartet. Nun k¨onnen sie den Befehl zum Wechseln in ihr
¨
¨
Ubungsverzeichnis
eingeben cd ... Um die Anderungen
zu speichern, dr¨
ucken sie
’Esc’ ’:’ ’w’. vi wechselt nun in den File-Modus ’w’ steht f¨
ur write ... so einfach
ist das.
Abbildung 11.24: Editieren und speichern
112
Befehl
i
a
Esc:
w
q
q!
11.3.3
KAPITEL 11 SOFTWARE-INSTALLATION
Wirkung
Wechseln in den Insert/Einf¨
uge-Modus
Wechseln in den Append/Anh¨angen-Modus
Wechseln in den Kommando-Modus
Write: Datei speichern (im Kommando-Modus)
¨
Quit: Datei ohne Anderung
verlassen (im Kommando-Modus)
¨
Quit: Datei ohne Anderung
verlassen (im Kommando-Modus)
Make
Mit den Make utilities k¨onnen ganze Projekte kompiliert werden, die aus vielen
Quelltext-Dateien bestehen. Nachfolgend sehen sie die Instruktionen des makefile f¨
ur die Kompilierung unseres Projekts. Dabei werden die Quell-Dateien
main.cpp und student.cpp kompiliert, gelinkt und die ausf¨
uhrbare Datei a.exe
erzeugt.
#
OPTFLAG = -O3
C++
= g++ $(OPTFLAG) -Wall
CFile = main.cpp student.cpp
OFile = main.o student.o
.SUFFIXES: .o .cpp .h
.cpp.o:
$(C++) -c -o $*.o
$<
main: $(OFile)
$(C++) -o main $(OFile)
clean:
rm -f *.o
11.4 QT INSTALLATION
11.4
Qt Installation
Qt installation
113
114
KAPITEL 11 SOFTWARE-INSTALLATION
Zur Qt Installation gehen sie auf folgende Web-Seite und folgen den Schritten
gem¨
aß den Abbildungen: http://www.qtsoftware.com/products/. W¨ahlen die
freie LGPL Lizenz.
Dabei wird die Installationsdatei f¨
ur das entsprechende Betriebssystem heruntergeladen (Abb. 11.25).
Abbildung 11.25: Qt Installationsdatei f¨
ur Windows
Nach der Installation haben sie den Qt Creator zur Verf¨
ugung (Abb. 11.26).
Abbildung 11.26: Qt Creator
Kapitel 12
Questions
12.1
Testfragen - Kapitel 1 - Einfu
¨ hrung
1. Was bedeutet das ++ im Namen der Programmiersprache C++ ?
2. Ist C++ eine standardisierte Programmiersprache ?
3. Was ist der Unterschied zwischen C und C++ ?
4. Was sind sogenannte Programmier-Paradigmen ?
5. Welche verschiedenen Programmier-Paradigmen kennen sie und worin unterscheiden sie sich ?
6. Welches Paradigma verfolgen wir in der Vorlesung ?
7. Was ist objekt-orientierte Programmierung ?
8. Was ist ein Kompiler ?
9. Erkl¨
aren sie die einzelnen Schritte bei einer Kompilierung (s. Abb. 1.4).
¨
10. Welchen Kompiler benutzen sie f¨
ur die C++ Ubungen
?
11. Welche Funktion ben¨
otigt jedes C oder C++ Programm ?
12. Was ist der Typ einer Funktion ?
13. Was ist eine Parameterliste einer Funktion ?
14. Was ist der R¨
uckgabewert einer Funktion ?
115
116
12.2
KAPITEL 12 QUESTIONS
Testfragen - Kapitel 2 - Datentypen
1. Was ist der genaueste Datentyp in C++ ?
2. Wie groß ist der Speicherbedarf von einem string Datentyp ?
3. Mit welcher Anweisung k¨onnen wir den Speicherbedarf von elementaren
Datentypen ermitteln ?
4. Was sind Escape-Sequenzen ?
5. Was ist der Unterschied zwischen den Escape-Sequenzen \n und \r ?
6. Was ist die C++ Entsprechung der Klasse cout f¨
ur einen Zeilenumbruch
?
12.3
Testfragen - Kapitel 3 - Ein- und Ausgabe
I
1. Sind sie mit der Tab. 2.2 einverstanden ?
2. Welche Ein- und Ausgabeger¨ate kennen sie ?
3. Welche Klasse ben¨otigen wir f¨
ur die Standard-Ein- und Ausgabe ?
4. Was ist die Basis-Klasse f¨
ur alle Ein- und Ausgaben in C++ ?
5. Mit welcher Klasse k¨onnen wir sowohl Eingabe- als auch Ausgabestr¨ome
benutzen ?
6. Welche Include-Datei ist notwendig, um mit I/O-Str¨omen arbeiten zu
k¨
onnen ?
7. Wozu dient der Zusatz using namespace std; nach dem Include von
Standard-Klassen, wie I/O Streams ?
8. Was bewirken die Stream-Operatoren << und >> ?
9. Was bewirken die Flags oct, dec, hex f¨
ur die formatierte Ausgabe von
Ganzzahlen ? (ToDo)
10. Wie kann ich die Genauigkeit der Ausgabe von Gleikomma-Zahlen festlegen ?
11. Wie kann man den Speicherbedarf einer Variable ermitteln ? Schreiben
sie die C++ Anweisung f¨
ur die Berechnung des Speicherbedarfs f¨
ur eine
doppelt-genaue Gleitkomma-Zahl.
12.4 TESTFRAGEN - KAPITEL 4 - KLASSEN
12.4
117
Testfragen - Kapitel 4 - Klassen
1. Geben sie eine Definition von C++ Klassen mit eigenen Worten (max 5
S¨
atze).
2. Was ist ein benutzerdefinierter Datentyp ?
3. Welches Datennschutz-Konzept gibt es f¨
ur Klassen ?
4. Wozu brauchen wir zwei Dateien f¨
ur Klassen, eine H (Header) Datei und
eine CPP (Quelltext) Datei ?
5. Was ist ein Inklude / Include ?
6. Was ist eine Instanz einer Klasse ?
7. Worin besteht der Unterschied zwischen den Anweisungen: CStudent m std 1
und CStudent* m std 2 ?
8. Was ist ein Konstruktor einer Klasse ?
9. Was ist das Gegenst¨
uck zum Klassen-Konstruktor ?
10. Wie k¨
onnen Daten / Variablen einer Klasse initialisiert werden ?
11. Schreiben sie den Quelltext f¨
ur den Klassen-Konstruktor und weisen sie
den Variablen name first und name last ihren eigenen Namen zu.
12. Was verbirgt sich hinter der Anweisung: CStudent* m std = new CStudent()
?
13. Was ist der Unterschied zwischen CStudent und CStudent() ?
14. Wie kann ich meine Daten gegen einen externen Zugriff sch¨
utzen ?
12.5
Testfragen - Kapitel 5 - Strings
1. Welche Klasse bietet uns C++ zur Verarbeitung von Zeichenketten an ?
2. Welchen Include ben¨
otigen wir f¨
ur die Arbeit mit Zeichenketten ?
3. Wof¨
ur ist die Anweisung using namespace std n¨
utzlich ?
4. M¨
ussen wir selber Speicherplatz f¨
ur C++ Zeichenketten (Strings) reservieren ?
5. Wie k¨
onnen wir einen String, sagen wir mit der Zeichenkette ”Das ist eine
gute Frage”, initialisieren ?
6. Wie k¨
onnen wir zwei Strings, ihren Vor- und Nachnahmen, miteinander
verbinden ?
118
KAPITEL 12 QUESTIONS
7. Mit welcher string Funktion kann ich Zeichenketten miteinander vergleichen ?
8. Schreiben sie eine Anweisung zum Vergleich der Klassen-Variable
m std− >name last mit ihrem Nachnamen ?
9. Mit welcher string Funktion kann ich Zeichenketten suchen ?
10. Schreiben sie eine Anweisung zum Suchen ihres Vornamens in der KlassenVariable m std− >name first ?
11. Mit welcher string Funktion kann ich Teile in Zeichenketten erstetzen ?
12. Wie k¨
onnen wir die L¨ange der in einem Objekt der Klasse std::string
verwalteteten Zeichenkette ermitteln ?
13. Schreiben sie die Anweisungen, um ihren Nachnamen in die Zeichenkette
”JAMES BOND” nach ”JAMES” einzuf¨
ugen ?
14. Was passiert, wenn ihr Nachname l¨anger als ”BOND” ist ?
15. Mit welcher string Funktion k¨onnen wir Zeichen in einem String l¨oschen ?
16. Wir haben gesehen, dass es verschiedene Daten-Typen f¨
ur Zeichenketten
in C, C++, MFC, .NET und Qt gibt. Zeichenketten geh¨oren zu den wichtigsten Daten-Typen bei der Programmierung. Wie k¨onnen wir einen C++
string in eine C Zeichenkette (char) umwandeln ?
17. K¨
onnen wir eine .NET Zeichenkette (String∧) in eine C++ Zeichenkette
(string) umwandeln ?
18. Was ist ein stringstream ?
19. Welchen Include ben¨otigen wir f¨
ur die Arbeit mit Stringstreams ?
12.6
Testfragen - Kapitel 6 - Ein- und Ausgabe
II
1. Was ist die Basis-Klasse f¨
ur alle Ein- und Ausgaben in C++ ?
2. Was sind die C++ Klassen f¨
ur das Lesen und Schreiben von Dateien ?
3. Welchen Include ben¨otigen wir f¨
ur das Arbeiten mit I/O File-Klassen ?
4. Was sind die Standard-Flags f¨
ur File-Streams (Lesen und Schreiben) ?
5. Mit welchem Flag k¨onnen wir zu schreibende Daten an eine existierende
Datei anh¨
angen ?
6. Was ist der Unterschied zwischen ASCII- und Bin¨ar-Formaten ?
12.7 TESTFRAGEN - KAPITEL 7 - REFERENZEN UND ZEIGER
119
7. Mit welchem Flag k¨
onnen wir Daten in einem Bin¨ar-Format schreiben ?
Mit welcher Anweisung wird ein File ge¨offnet ? Mit welcher Anweisung
wird ein File geschlossen ?
8. Was bewirken die Stream-Operatoren << und >> ?
9. Wie k¨
onnen wir mit Dateinamen in unserem Hauptprogramm main(...)
arbeiten ?
10. Welche Anweisung ben¨
otigen wir f¨
ur die Erzeugung einer Instanz f¨
ur einen
Eingabe-Strom ?
11. Welche Anweisung ben¨
otigen wir f¨
ur die Erzeugung einer Instanz f¨
ur einen
Ausgabe-Strom ?
12. F¨
ur die Erstellung einer Datenbank ist es wichtig einzelnen Datens¨atze zu
trennen. Wie k¨
onnen wir soetwas in der Datenbank-Datei bewerkstelligen
?
13. Ist es wichtig das Ende einer Datenbank-Datei, z.B. mit einem Schl¨
usselwort #STOP, zu markieren ?
¨
14. Mit welcher Abfrage k¨
onne wir pr¨
ufen, ob die Offnung
einer Datei erfolgreich war ?
15. Mit welcher Anweisung k¨
onnen wir die aktuell gelesene Position in einer
ge¨
offneten Datei abfragen ?
16. Mit welcher Anweisung k¨
onnen wir zu einer bestimmten Position in einer
ge¨
offneten Datei springen ?
17. Mit welcher Anweisung k¨
onnen wir eine komplette Zeile aus ge¨offneten
Datei auslesen ?
12.7
Testfragen - Kapitel 7 - Referenzen und
Zeiger
1. Was ist &x ? (x ist ein beliebiger Datenobjekt T, z.B. eine Gleitkommazahl: double x)
2. Was ist eine Referenz &ref?
3. Was bedeutet die Anweisung: &ref = x?
4. Erkl¨
aren sie kurz (mit eigenen Worten) das Zeiger-Konzept in C++?
5. Was bewirkt der NULL Zeiger, d.h. *ptr = NULL ?
6. Was bedeutet die Anweisung: ptr = x?
120
KAPITEL 12 QUESTIONS
7. M¨
ussen Referenzen (&) und Zeiger (*) auf Daten-Objekte initialisiert werden ?
8. Was bewirkt die Definition long l[1000] speichertechnisch ?
9. Wie groß ist der Speicherbedarf des statischen Datenobjekts long l[1000]
?
10. Wie groß ist der Speicherbedarf des dynamische Datenobjekts long* ptr l
= new long[1000] ?
11. Woher kommt der Unterschied (4 Byte auf einem 32Bit Rechner) im
Speicherbedarf zwischen statischen und dynamischen Datenobjekten.
12. Zusatzfrage: Was bedeutet die Definition **ptrptr (Zeiger auf Zeiger), was
f¨
ur ein Datenkonstrukt entsteht ?
12.8
Testfragen - Kapitel 8 - Container
1. Was sind C++ Container ?
2. Welche Typen von C++ Containern kennen sie ?
3. Worin besteht der Unterschied zwischen sequentiellen und assoziativen
Containern ?
4. Welche sequentiellen Container kennen sie ?
5. Erkl¨
aren sie die Syntax des Vektor-Containers: vector<int>my vector .
6. Was ist der Unterschied zwischen Vektoren und Listen ?
7. Was sind die Gemeinsamkeiten von Vektoren und Listen ?
8. Welcher Include ist notwendig f¨
ur das Arbeiten mit Vektoren ?
9. Welcher Include ist notwendig f¨
ur das Arbeiten mit Listen ?
10. Ben¨
otigen wir den Zusatz (Namensraum) using namespace std, wenn ja
warum ?
11. Mit welcher Instruktion k¨onnen Elemente in Vektoren und Listen einf¨
ugen
? Nennen sie mindestens zwei M¨oglichkeiten.
12. Wo werden sequentielle Container-Elemente mit der Instruktion push back(T)
eingef¨
ugt ?
13. Mit welcher Anweisung k¨onnen wir die L¨ange von sequentiellen ContainerElementen bestimmen ?
12.9 TESTFRAGEN - KAPITEL 9 - ANDERE SPRACHELEMENTE
121
14. Mit welcher Anweisung k¨
onnen wir einen Vektor platt machen (d.h. alle
Elemente l¨
oschen) ?
15. Wie k¨
onnen wir auf ein Vektor-Element, sagen wir das 17te Element des
Vektors vector<int>my vector, direkt zugreifen ?
16. Quellcode verstehen: Erkl¨
aren sie die Struktur (1,2,3) der DB-Lese-Funktion
¨
STDRead(ifstream& std file) in der Ubung
8.2.2. Beginnen sie mit der Parameterliste.
17. Wie k¨
onnen wir unsere Studenten-Klasse CStudent in die DB-Anwendung
¨
(Ubung
8.2.1) einbinden ?
¨
18. Was ist eigentliche Lesefunktion f¨
ur unsere Studenten-Datens¨atze (Ubung
8.2.2) ?
19. Mit welchem Befehl k¨
onnen wir die Reihenfolge von Listen-Elementen
umkehren ?
20. K¨
onnen wir Listen-Elemente sortieren, wenn ja wie, mit welcher Instruktion ?
21. Mit welchem Befehl k¨
onnen wir mehrere Listen zusammenf¨
uhren ?
22. K¨
onnen wir doppelte Elemente aus einer Liste entfernen sortieren, wenn
ja wie, mit welcher Instruktion ?
23. Was ist ein Iterator ?
24. Quellcode verstehen: Erkl¨
aren sie die Funktion void
¨
display(list<int>my list) der Ubung
8.3. Beginnen sie mit der Parameterliste.
25. Wie k¨
onnen wir Elemente aus einer Liste entfernen ? Nennen sie mindestens zwei M¨
oglichkeiten.
12.9
Testfragen - Kapitel 9 - Andere Sprachelemente
1. Was sind Kontrollstrukturen, welche kennen sie ?
2. Bei welcher logischen Bedingung wird eine if(...)-Anweisung ausgef¨
uhrt
?
3. Lassen sich Kontroll-Strukturen verschachteln ?
4. Mit welcher Kontrollstruktur k¨onnen wir Fallunterscheidungen programmieren ?
122
KAPITEL 12 QUESTIONS
5. Welche Ausdr¨
ucke k¨onnen wir bei der switch-case Kontrollstruktur benutzen ?
6. Wie kann ich eine Kompiler-Direktive an- und ausschalten ?
¨
7. Schreiben sie die Ubung
9.2.2.2 f¨
ur die Benutzung von #ifndef anstelle
von #ifdef um.
8. Erl¨
autern sie den Kopf der for-Schleife: for(int i=0;i<stop;i++), welchen Daten-Typ hat stop ?
9. Was ist eine Endlos-Schleife, wie kommen wir daraus ?
10. Was sind Namensbereiche ?
11. Was m¨
ussen wir tun, um die Arbeit mit C++ Standard-Klassen zu vereinfachen, d.h anstelle von std::my string() direkt my string() benutzen
zu k¨
onnen ?
12. Was sind Kompiler-Direktiven, was bewirken diese ?
13. Wie k¨
onnen wir Kompiler-Direktiven an- und ausschalten ?
14. Worin besteht der Unterschied bei Includes mit eckigen Klammern < ... >
bzw. mit G¨
ansef¨
ußchen ”...” ?
¨
15. Schreiben sie die Ubung
9.2.2.2 f¨
ur die Benutzung von #ifndef anstelle
von #ifdef um ?
16. Was sind Makros ?
17. Welche beiden Einsatzm¨oglickeiten von Makros gibt es ?
18. Worin besteht die Gefahr, Makros als Funktionsersatz zu benutzen ?
Literaturverzeichnis
[1] Stroustrup B. The programming languages C++. Addison-Wesley, Reading,
1991.
[2] Blanchette J and Summerfield M. C++ GUI Programming with Qt 4. Prentice Hall, Boston, 2006.
[3] Kolditz O. Computational methods in environmental fluid mechanics. Springer, Berlin-Heidelberg, 2002.
[4] Breymann U. C++ Einf¨
uhrung und professionelle Programmierung. Hanser,
M¨
unchen-Wien, 2001.
[5] Kirch-Prinz U and Prinz P. C++ Lernen und professionell anwenden. mitp,
Heidelberg, 2007.
123
Inhaltsverzeichnis
Part I - C++ Basics
6
1 Einf¨
uhrung
7
1.1
Historisches . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
8
1.2
Paradigmen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
9
1.3
Compiler
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
11
1.3.1
GNU . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
12
1.3.2
MS Visual C++ . . . . . . . . . . . . . . . . . . . . . . .
13
1.3.3
Qt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
13
”Hello World” . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
14
1.4.1
Grundlagen . . . . . . . . . . . . . . . . . . . . . . . . . .
14
1.4.2
Exercise E1 . . . . . . . . . . . . . . . . . . . . . . . . . .
15
1.5
Students Forum . . . . . . . . . . . . . . . . . . . . . . . . . . . .
16
1.6
Testfragen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
17
1.4
2 Datentypen
19
2.1
Elementare Datentypen . . . . . . . . . . . . . . . . . . . . . . .
19
2.2
Speicherbedarf . . . . . . . . . . . . . . . . . . . . . . . . . . . .
20
2.3
Escape-Sequenzen . . . . . . . . . . . . . . . . . . . . . . . . . .
20
2.4
Testfragen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
21
3 Ein- und Ausgabe
22
3.1
Die Standard-Streams . . . . . . . . . . . . . . . . . . . . . . . .
24
3.2
Formatierte Ausgaben . . . . . . . . . . . . . . . . . . . . . . . .
24
3.2.1
24
Formatierte Ausgabe von Ganzzahlen . . . . . . . . . . .
124
INHALTSVERZEICHNIS
3.3
125
3.2.2
Formatierte Ausgabe von Gleitpunktzahlen . . . . . . . .
25
3.2.3
Ausgabe von Speicherbedarf . . . . . . . . . . . . . . . . .
25
Testfragen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
26
4 Klassen
27
4.1
Daten-Abstraktion . . . . . . . . . . . . . . . . . . . . . . . . . .
28
4.2
Klassen-Deklaration . . . . . . . . . . . . . . . . . . . . . . . . .
29
4.3
Instanzen einer Klasse . . . . . . . . . . . . . . . . . . . . . . . .
29
4.4
Konstruktor und Destruktor . . . . . . . . . . . . . . . . . . . . .
31
4.5
Dateninitialisierung mit dem Konstruktor . . . . . . . . . . . . .
32
4.6
Datenschutz . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
33
4.7
Testfragen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
35
5 Strings
36
5.1
Die Standardklasse string . . . . . . . . . . . . . . . . . . . . . .
36
5.2
Operationen mit strings . . . . . . . . . . . . . . . . . . . . . . .
37
5.2.1
Initialisieren von strings . . . . . . . . . . . . . . . . . . .
37
5.2.2
Zuweisen von strings . . . . . . . . . . . . . . . . . . . . .
38
5.2.3
Verketten von strings
. . . . . . . . . . . . . . . . . . . .
38
5.2.4
Vergleichen von strings . . . . . . . . . . . . . . . . . . . .
38
5.2.5
Suchen in strings . . . . . . . . . . . . . . . . . . . . . . .
39
5.2.6
Einf¨
ugen in strings . . . . . . . . . . . . . . . . . . . . . .
39
5.2.7
Ersetzen in strings . . . . . . . . . . . . . . . . . . . . . .
40
5.2.8
L¨
oschen in strings . . . . . . . . . . . . . . . . . . . . . .
40
5.2.9
Umwandeln von strings in char . . . . . . . . . . . . . . .
41
5.2.10 Auswerten von Strings: Stringstreams . . . . . . . . . . .
41
Testfragen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
42
5.3
6 Ein- und Ausgabe - II
43
6.1
Die fstream Klassen . . . . . . . . . . . . . . . . . . . . . . . . .
43
6.2
Arbeiten mit File-Streams . . . . . . . . . . . . . . . . . . . . . .
44
6.2.1
File-Streams anlegen . . . . . . . . . . . . . . . . . . . . .
44
6.2.2
File-Streams schließen . . . . . . . . . . . . . . . . . . . .
¨
Ubung:
Eine einfache Kopierfunktion . . . . . . . . . . . .
44
6.2.3
44
126
INHALTSVERZEICHNIS
6.2.4
¨
Ubung:
Ein einfacher Konverter . . . . . . . . . . . . . . .
46
6.2.5
Einschub: Erstes Arbeiten mit MS VC++ . . . . . . . . .
47
6.3
File-Streams und Klassen . . . . . . . . . . . . . . . . . . . . . .
50
6.4
fstream Methoden . . . . . . . . . . . . . . . . . . . . . . . . . .
53
6.5
Testfragen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
54
7 Referenzen und Zeiger
7.1
Referenzen
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
55
56
7.1.1
Das Call-by-reference Prinzip - Referenzen als Parameter
56
7.1.2
Referenzen als R¨
uckgabe-Wert . . . . . . . . . . . . . . .
57
Zeiger . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
57
7.2.1
Definition von Zeigern . . . . . . . . . . . . . . . . . . . .
58
7.2.2
NULL Zeiger . . . . . . . . . . . . . . . . . . . . . . . . .
58
7.2.3
Zeiger als Parameter . . . . . . . . . . . . . . . . . . . . .
59
Zeiger und Arrays . . . . . . . . . . . . . . . . . . . . . . . . . .
59
7.3.1
Statische Objekte . . . . . . . . . . . . . . . . . . . . . . .
59
7.3.2
Dynamische Objekte . . . . . . . . . . . . . . . . . . . . .
59
7.4
Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
60
7.5
Testfragen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
62
7.2
7.3
8 Container
63
8.1
Sequentielle Container . . . . . . . . . . . . . . . . . . . . . . . .
64
8.2
Vectors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
65
8.2.1
Defining vectors . . . . . . . . . . . . . . . . . . . . . . .
67
8.2.2
Vectors and data base . . . . . . . . . . . . . . . . . . . .
67
8.2.3
Updating your data base entry . . . . . . . . . . . . . . .
69
8.3
Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
70
8.4
Testfragen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
72
9 Andere Sprachelemente
9.1
74
Kontrollstrukturen . . . . . . . . . . . . . . . . . . . . . . . . . .
74
9.1.1
if-else . . . . . . . . . . . . . . . . . . . . . . . . . . . .
75
9.1.2
switch-case . . . . . . . . . . . . . . . . . . . . . . . . .
75
9.1.3
for
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
76
9.2
9.3
9.1.4
while . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
76
9.1.5
continue, break, return . . . . . . . . . . . . . . . . .
76
G¨
ultigkeitsbereiche . . . . . . . . . . . . . . . . . . . . . . . . . .
77
9.2.1
Namensbereiche . . . . . . . . . . . . . . . . . . . . . . .
77
9.2.2
Compiler-Direktiven – #
. . . . . . . . . . . . . . . . . .
77
Testfragen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
79
Part II - Visual C++ mit Qt
81
10 Qt
82
10.1 Hello Qt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
82
10.2 Executable von der Konsole starten . . . . . . . . . . . . . . . . .
83
10.3 Quit - Schalt߬
achen . . . . . . . . . . . . . . . . . . . . . . . . .
84
10.4 Dialoge . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
85
10.5 Qt Projekt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
89
Part III - Anlagen / Software
94
11 Software-Installation
95
11.1 Glossar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
96
11.2 cygwin Installation . . . . . . . . . . . . . . . . . . . . . . . . . .
97
11.3 LINUX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106
¨
11.3.1 Ubersicht
einiger grundlegenden Linux-Befehle . . . . . . 106
11.3.2 Profile . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
11.3.3 Make . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112
11.4 Qt Installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
12 Questions
115
12.1 Testfragen - Kapitel 1 - Einf¨
uhrung . . . . . . . . . . . . . . . . . 115
12.2 Testfragen - Kapitel 2 - Datentypen . . . . . . . . . . . . . . . . 116
12.3 Testfragen - Kapitel 3 - Ein- und Ausgabe I . . . . . . . . . . . . 116
12.4 Testfragen - Kapitel 4 - Klassen . . . . . . . . . . . . . . . . . . . 117
12.5 Testfragen - Kapitel 5 - Strings . . . . . . . . . . . . . . . . . . . 117
12.6 Testfragen - Kapitel 6 - Ein- und Ausgabe II . . . . . . . . . . . 118
12.7 Testfragen - Kapitel 7 - Referenzen und Zeiger . . . . . . . . . . 119
128
INHALTSVERZEICHNIS
12.8 Testfragen - Kapitel 8 - Container . . . . . . . . . . . . . . . . . 120
12.9 Testfragen - Kapitel 9 - Andere Sprachelemente . . . . . . . . . . 121
Was this manual useful for you? yes no
Thank you for your participation!

* Your assessment is very important for improving the work of artificial intelligence, which forms the content of this project

Download PDF

advertisement