Springer-Lehrbuch Martin Schader Stefan Kuhlins Programmieren in C++ Einfiihrung in den Sprachstandard C++ Version 3.0 Mit 25 Abbildungen Springer-Verlag Berlin Heidelberg New York London Paris Tokyo Hong Kong Barcelona Budapest Professor Dr. Martin Schader Dipl.-Wirtsch.-Inf. Stefan KuWins Universität Mannheim Lehrstuhl für Wirtschaftsinformatik m Schloß D-6800 Mannheim 1 ISBN-13: 978-3-540-56524-6 DOI: 10.1007/978-3-642-97490-8 e-ISBN-13: 978-3-642-97490-8 Dieses Werk ist urheberrechtlich geschützt. Die dadurch begründeten Rechte, insbesondere die der Übersetzung, des Nachdruckes, des Vortrags, der Entnahme von Abbildungen und Tabellen, der Funksendungen, der Mikroverfilmung oder der Vervielfältigung aufanderen Wegen und der Speicherung in Datenverarbeitungsanlagen, bleiben, auch bei nur auszugsweiser Verwertung, vorbehalten. Eine Vervielfältigung dieses Werkes oder von Teilen dieses Werkes ist auch im Einzelfall nur in den Grenzen der gesetzlichen Bestimmungen des Urheberrechtsgesetzes der Bundesrepublik Deutschland vom 9. September 1965 in der Fassung vom 24. Juni 1985 zulässig. Sie ist grundsätzlich vergütungspflichtig. Zuwiderhandlungen unterliegen den Strafbestimmungen des Urheberrechtsgesetzes. © Springer-Verlag Heidelberg 1993 Die Wiedergabe von Gebrauchsnamen, Handelsnamen, Warenbezeichnungen usw. in diesem Werk berechtigt auch ohne besondere Kennzeichnung nicht zu der Annahme, daß solche Namen im Sinne der Warenzeichen- und Markenschutz-Gesetzgebung als frei zu betrachten wären und daher von jedermann benutzt werden dürften. 4217130-543210 - Gedruckt auf säurefreiem Papier Vorwort Der Einsatz objektorientierter Techniken in allen Phasen der Softwareentwicklung - in der Analyse- und Designphase und bei der Implementierung - hat das Interesse an der Programmiersprache C++ in den letzten Jahren ständig größer werden lassen. Entsprechend hat sich auch das Angebot verfügbarer C++-Compiler auf unterschiedlichsten Hardware-Plattformen und Betriebssystemen stetig vergrößert. Bei der Erstellung dieses Lehrbuchs haben wir Borland C++ 3.1 unter MS-DOS Version 5.0 und AT&T cfront 3.0.1 unter Sun-OS 4.1.3 benutzt, da es sich dabei unserer Ansicht nach um die derzeit am weitesten verbreiteten Compiler für MSDOS- bzw. UNIX-Systeme handelt. Alle in den nachfolgenden Kapiteln vorgestellten Beispielprogramme können unverändert mit beiden Compilern übersetzt werden. Auf Unterschiede oder Einschränkungen bei den Kurzbeispielen weisen wir jeweils im entsprechenden Zusammenhang hin. Die Sprache C++ befindet sich derzeit noch im Stadium der endgültigen Normierung. Es gibt jedoch ein C++-Komitee (Technical Committee X3J16 Programming Language) des ANSI (American National Standards Institute), das 1990 seine Arbeit aufgenommen hat. Dieses Komitee hat die Publikation M.A. Ellis, B. Stroustrup, The Annotated C++ Reference Manual, Addison-Wesley, Reading, 1990 als Grundlage (base document) für die formale St~ndardisierung gewählt. Die Verabschiedung des Standards wird nicht vor 1995 erwartet. Die vom Komitee jeweils diskutierten Unterlagen kann man als Working Paper for Draft Proposed American National Standard for Information Systems - Programming Langua,ge C++ vom X3 Secretariat, CBEMA, 1250 Eye Street, NW Suite 200, Washington DC 20005-3922, USA anfordern. Der im vorliegenden Buch beschriebene Sprachumfang ist der in Ellis, Stroustrup (1990) beschriebene - aktualisiert durch das neueste AT&T C++ Reference Manual (derzeitiger Stand: Mai 1991). Die jeweils aktuellste Version dieses Manuals kann direkt über das AT&T Customer Information Center, 2855 N. Franklin Road, Indianapolis, IN 46219-1385, USA bezogen werden. Unser Buch beinhaltet keine Darstellung des gesamten (noch nicht vollständig normierten) Inhalts der C++-Standardbibliothek; nur die benutzten Funktionen werden kurz erläutert. Das Buch ist aus einem Vorlesungszyklus über objektorientierte Methoden, der an der Universität Mannheim gehalten wird, entstanden. Es wendet sich an Leser, die über Grundkenntnisse von Rechnern und ihrer Programmierung verfügen und mit den Begriffen Compiler, Linker, ... und ihrer Umgebung vertraut sind. Die einzelnen Sprachkonstrukte werden anhand vieler Programmfragmente und kleiner Beispielprogramme erklärt. Diese Beispiele sind in keiner Weise als vollständig sondern lediglich als illustrativ für den jeweils diskutierten Gegenstand anzusehen; sie sind in der Regel sehr kurz gehalten und es wurde wenig Wert auf Algorithmik oder möglichen Effizienzgewinn durch Schreiben von "C++-Puzzles" gelegt. Fast immer wurde auf Fehlerbehandlung und Kommentare verzichtet, die beide bei für vi den praktischen Einsatz vorgesehenen Programmen unerläßlich sind. Eine komplette Fehlerbehandlung und Kommentierung würde den Umfang der Programme mindestens verdoppeln oder verdreifachen. Die Leser müssen sich darüber im klaren sein, daß hier noch eigenständig weiterentwickelt werden muß. Wir empfehlen, die Programmbeispiele parallel zum Lesen sukzessiv fortzuschreiben. Wenn im Text auf eine Klasse verwiesen wird, ist immer die bis dahin implementierte Version gemeint. Am Ende der meisten Kapitel ist eine Reihe von Übungsaufgaben zusammengestellt, mit denen der behandelte Stoff vertieft werden kann. Gegen Einsendung einer MS-DOS-formatierten 3t"-Diskette mit frankiertem Rückumschlag an die auf den Umschlagseiten angegebene Anschrift sind unsere Lösungsvorschläge erhältlich. Über Mitteilungen und Anregungen der Leserinnen und Leser würden wir uns freuen. Wer uns einen Fehler (gleichgültig welcher Art) zuerst mitteilt, wird ggf. im Vorwort der nächsten Auflage namentlich erwähnt. Dr. Werner A. Müller und seinen Mitarbeitern beim Springer-Verlag, Heidelberg, gilt unser Dank für die - wie immer - ausgezeichnete Zusammenarbeit. Mannheim, Januar 1993 Martin Schader, Stefan K uhlins Inhalt 1 Einleitung 1.1 Grundbegriffe 1.2 Syntaxnotation 1 1 2 2 Lexikalische Konventionen 2.1 Ein erstes Beispiel . . . 2.2 Lexikalische Elemente. 2.3 Kommentare.. 2.4 Bezeichner . . . 2.5 Schlüsselwörter 2.6 Operatoren .. 2.7 Header-Dateien 3 3 3 Vordefinierte Datentypen 9 4 Literalkonstanten 4.1 Ganzzahlige Konstanten 4.2 Zeichenkonstanten .. 4.3 Gleitpunktkonstanten . 4.4 Zeichenketten 4.5 Beispiele........ 13 5 Variablen und Konstanten 5.1 Einleitung . . . . . . . . . . . . . . . . . . 5.2 Deklaration und Definition von Variablen. 5.3 Symbolische Konstanten 5.4 L-Werte 5.5 Beispiel . . . . . . . . . 19 6 Typumwandlungen und Ausdrücke 6.1 Standardkonversionen . 6.2 Ausdrücke.... 6.3 Übungsaufgaben 27 7 Anweisungen 7.1 Einleitung . . . . . . . 7.2 Ausdrucksanweisungen 7.3 Auswahlanweisungen 7.4 Wiederholungsanweisungen . 7.5 Sprunganweisungen 7.6 Beispiel . . . . . . . . . . . 45 45 4 4 4 5 5 6 13 14 15 16 17 19 21 23 24 24 27 30 42 46 47 50 53 54 viii 7.7 Übungsaufgaben . . . . . . . . . . . . . . . . . . . . . . . . . . 55 8 Abgeleitete Datentypen 8.1 Felder . . . . 8.2 Zeichenfelder .. 8.3 Zeiger . . . . . . 8.4 Zeigerarithmetik 8.5 Zeiger und Felder 8.6 Die Operatoren new und delete . 8.7 Referenzen . . . . . . . . 8.8 Aufzählungstypen . . . . . 8.9 Typnamen und typedef . 8.10 Der abgeleitete Typ void* 8.11 Übungsaufgaben . . . . . 57 57 61 62 66 68 9 Typumwandlungen 9.1 Standardkonversionen . 9.2 Explizite Typumwandlungen 9.3 Übungsaufgaben . . . . . . 87 87 87 90 10 Geltungsbereiche und Lebensdauer 10.1 Geltungsbereiche . . . . . . . . 10.2 Die Lebensdauer von Objekten 10.3 Übungsaufgaben . . . . . . . . 91 91 95 98 11 Funktionen 11.1 Deklaration und Definition von Funktionen. 11.2 Funktionsaufruf und Argumentübergabe 11.3 Die Rückgabe von Funktionswerten 11.4 Referenzargumente .. 11.5 Felder als Argumente . . . . . 11.6 Zeiger auf Funktionen . . . . 11.7 Der Geltungsbereich Funktion 11.8 Standardargumente . . . . . . 11.9 Unspezifizierte Argumente .. 11.10 Die Funktionen mainO und exitO 11.11 inline-Funktionen . 11.12 Übungsaufgaben . . . . . . . 72 77 80 81 83 85 101 · 101 · 104 .106 · 107 · 109 · 111 .114 · 115 .116 · 119 .119 · 121 125 12 Externe und interne Bindung 13 Überladene Funktionsnamen 13.1 Einleitung . . . . . . . . . . . . . . . . 13.2 Funktionen mit einem Argument .. . 13.3 Funktionen mit mehreren Argumenten 13.4 Zeiger auf überladene Funktionen . . . · · · · 133 133 136 140 142 ix 13.5 Übungsaufgaben · 143 14 Klassen 14.1 Deklaration und Definition von Klassen. 14.2 Klassenobjekte . . . . . . . . . . . . . 14.3 Der Geltungsbereich Klasse . . . . . . 14.4 Die Spezifizierung von Zugriffsrechten . 14.5 Der Zeiger this . . . . . . . . . . . . . 14.6 Namensdeklarationen . . . . . . . . . . 14.7 Die Konstruktion von Klassenobjekten 14.8 Destruktoren . . . . . . . . . . . . . . 14.9 Als eonst deklarierte Elementfunktionen 14.10 friend-Funktionen . . . . . 14.11 statie Klassenelemente .. 14.12 inline-Elementfunktionen 14.13 Zeiger auf Klassenelemente 14.14 Klassenobjekte als Klassenelemente . 14.15 Lokale Typnamen . . . . . . . . 14.16 Bitfelder . . . . . . . . . . . . . 14.17 Die Bindung von Klassennamen . 14.18 Reader-Dateien. 14.19 Übungsaufgaben . . . . . . . . . 145 · 145 .147 · 148 · 152 · 155 · 156 · 160 · 167 · 169 .172 · 175 .179 · 181 · 185 · 188 · 189 · 191 · 194 · 197 15 Spezielle Konstruktoren 15.1 Der Copy-Konstruktor . . . . . . . . . . 15.2 Typumwandlungen mittels Konstruktor . 15.3 Übungsaufgaben . . . . . . . . . . . . . .201 · 205 .207 16 Überladene Operatoren 16.1 Einleitung . . . . . . . 16.2 Der Zuweisungsoperator = 16.3 Einstellige Operatoren .. 16.4 Zweistellige Operatoren .. 16.5 Typumwandlungen mittels Konversionsfunktion 16.6 Übungsaufgaben . . . . . . . . . . . . . . . . . .209 .210 · 212 · 215 · 219 · 221 17 Abgeleitete Klassen 17.1 Einfache Vererbung . . . . . . . . . . . . . . . . . . 17.2 Der Zugriff auf Klassenelemente . . . . . . . . . . . 17.3 Standardkonversionen von Zeigern und Referenzen. 17.4 Virtuelle Funktionen 17.5 Abstrakte Klassen. . . 17.6 Mehrfachvererbung . . 17.7 Virtuelle Basisklassen . 17.8 Spezielle Zugriffsrechte .225 .229 .233 .239 .245 .248 · 252 .256 201 209 225 x 17.9 Übungsaufgaben .260 18 Parametrisierte Funktionen und Klassen 18.1 Einleitung . . . . . . . . . . 18.2 Parametrisierte Funktionen 18.3 Parametrisierte Klassen. 18.4 Übungsaufgaben . . . . . . 265 · 265 · 266 .273 .284 19 Streams 19.1 Einleitung . . . . . . . . . . . . . . . . . . . . . . . 19.2 Formatierung . . . . . . . . . . . . . . . . . . . . . 19.3 Ein- und Ausgabe benutzerdefinierter Datenobjekte 19.4 Ein- und Ausgabe mit Dateien. 19.5 Übungsaufgaben . . . . . . . . . . . . . . . . . . . 287 .287 .287 .288 · 290 .292 Anhang A ASCII-Tabelle. B Arithmetische Standardkonversionen C Operatorprioritäten . D Syntaxregeln . . . E Die Klasse Liste .293 .294 .295 .296 · 298 Literaturverzeichnis Index 293 302 303 1 Einleitung In diesem Kapitel erläutern wir die drei für die Beschreibung jeder modernen Programmiersprache wichtigen Komponenten Symbolvorrat, Syntax und Semantik. Anschließend wird die im weiteren verwendete Notation der Syntaxregeln eingeführt. 1.1 Grundbegriffe Bei der Beschreibung einer Programmiersprache sind die folgenden drei Aspekte zu betrachten: - Die lexikalischen Elemente der Sprache. Die Menge der lexikalischen Elemente ist der sog. Symbolvorrat der Sprache. Hierin sind die Wörter und Interpunktionszeichen enthalten, aus denen sich korrekt gebildete Programme (das sind die Sätze der Sprache) zusammensetzen. Die lexikalischen Elemente von C++ werden in Kapitel 2 und Kapitel 4 diskutiert. Dort wird beschrieben, welche Form die Namen der in einem Programm auftretenden Variablen, Typen, Funktionen, etc. haben müssen, welche Namen für den Compiler eine feste Bedeutung haben, so daß sie vom Programmierer nicht mehr für eigene Zwecke verfügbar sind und wie Zahlen und andere Konstanten dargestellt werden. - Die Syntax der Sprache. Nicht jede Folge von lexikalischen Elementen ist bereits ein korrekt gebildetes Programm. Welche Symbolfolgen zulässige Sätze der Sprache (das sind Programme, die der Compiler versteht und übersetzen kann) bilden, wird durch die Syntax oder Grammatik der Sprache geregelt. Für die Beschreibung der Syntax von C++ verwenden wir Syntaxregeln, deren Format im nächsten Abschnitt beschrieben ist. - Die Semantik von Programmen. Die Semantik gibt zu jedem Programm die zugehörige Bedeutung an, beschreibt also, welche Aktionen das Programm ausführt, wie eingegebene Daten verarbeitet werden bzw. mit welchen Berechnungen Ausgaben vorbereitet 1. Einleitung 2 werden. Wir werden die Semantik von C++-Programmen umgangssprachlich, anhand vieler Beispiele, jeweils im Zusammenhang mit der Erläuterung neuer Syntaxregeln erklären. 1.2 Syntaxnotation Die Syntax einer Programmiersprache wird durch eine Zusammenstellung von Regeln (sog. Produktionsregeln) spezifiziert, die die korrekte Bildung von Programmen beschreiben. Zur Darstellung der Regeln benutzen wir die in B. W. Kernighan, D.M. Ritchie, The C Programming Language, Prentice Hall, 1978 eingeführte Notation. Jede Regel beginnt mit einem nichtterminalen Symbol, auf das ein Doppelpunkt und die Definition des Symbols folgen. Terminale Symbole sind in Schreibmaschinenschrift gesetzt - sie werden unverändert in den Programmtext übernommen. In der Definition auftretende nichtterminale Symbole sind in anderen Regeln definiert. Alternativen stehen in verschiedenen Zeilen. In wenigen Ausnahmen wird eine lange Liste von Alternativen auf einer Zeile angegeben; dies wird durch den Ausdruck "eins von" angezeigt. Ein optionales terminales oder nichtterminales Symbol erhält den Index opt. Beispielsweise beschreiben die beiden folgenden Regeln C+ +-Programm: Programm datei C++-Programm Programmdatei Programmdatei: Deklaration Programmdatei Deklaration daß ein C++-Programm aus einer oder mehreren Programmdateien besteht, die jeweils eine oder mehrere Deklarationen enthalten, und der Regel Deklaration: Dekl-Spezijiziererlisteopt Deklaratorlisteopt ; Asm-Deklaration Funktionsdejinition Template- Deklaration Bindungsspezijikation kann man entnehmen, daß eine Funktionsdefinition eine Deklaration ist. Die in diesem Lehrbuch zusammengestellten Syntaxregeln definieren die Sprache C++ nicht vollständig. Gelegentlich werden sie durch eine weniger formale, verbale Erläuterung ergänzt. Die obige erste Regel ist beispielsweise durch den Zusatz zu vervollständigen, daß jedes C++-Programm eine Funktionsdefinition enthalten muß, in der eine Funktion mit dem Namen main definiert wird. Somit ist ein einzelnes; kein C++-Programm. 2 Lexikalische Konventionen Anhand eines ersten Beispielprogramms werden wir in diesem Kapitel in die Grundlagen von C++ einführen. Dazu stellen wir die lexikalischen Elemente: Kommentare, Bezeichner, Schlüsselwörter und Operatoren vor. Außerdem wird das Übersetzen und Ausführen eines ersten C++-Programms besprochen. 2.1 Ein erstes Beispiel Wir beginnen dieses Kapitel mit einem einfachen Programm, das die Fläche eines Dreiecks bei gegebener Höhe und Grundseite berechnet: 1* prog-i * * Programm zur Berechnung der Flaeche eines Dreiecks * mit vorgegebener Hoehe und Grundseite. *1 #include <iostream.h> II vgl. Abschnitt Header-Dateien int mainO { int hoehe = 3; int grundseite 5; double flaeche hoehe*grundseite*0.5; cout « "Flaeche des Dreiecks: " « flaeche « return 0; '\n'; } Bei Benutzung von Borland C++ speichert man dieses Programm am besten unter dem Dateinamen prog-i. cpp ab und gibt, um es zu übersetzen, den Befehl bcc prog-i ein. Man erhält dann als Ergebnis das lauffähige Programm prog-i. exe, das mit der Eingabe prog-i gestartet werden kann. Für AT&T's cfront ist das zu 4 2. Lexikalische Konventionen übersetzende Programm mit dem Namen prog-l. C anzulegen. Der entsprechende Compiler-Aufruf lautet CC prog-1.C -0 prog-1. Als Resultat erhält man das ausführbare Programm prog-l, das wieder mit prog-l gestartet wird. Dieses Beispielprogramm wird in den folgenden Abschnitten dazu verwendet, die elementaren Sprachelemente näher zu erläutern. 2.2 Lexikalische Elemente Die kleinsten Einheiten, aus denen sich ein C++-Programm zusammensetzt, nennt man lexikalische Elemente. Sie werden in fünf Klassen eingeteilt: Bezeichner, Schlüsselwörter und Interpunktionszeichen, Literalkonstanten, Operatoren und Trenner. Zu den Trennern gehören Leerzeichen, Tabulatoren, Zeilenendezeichen, Seitenvorschübe und Kommentare. Sie werden dazu verwendet, die übrigen lexikalischen Elemente voneinander zu trennen. Zwischen aufeinanderfolgenden Bezeichnern, Schlüsselwörtern oder Literalkonstanten muß mindestens ein Trenner stehen - ansonsten werden Trenner vom Compiler ignoriert. Trenner, die nicht Kommentare sind, werden auch als" white space" bezeichnet, da die entsprechenden Zeichen bei der Ausgabe des Programms auf Drucker oder Monitor nicht sichtbar sind. Bei der Analyse eines Programmtextes werden vom Compiler immer die größtmöglichen lexikalischen Elemente gebildet, d.h. wenn ein kurzes in einem längeren Element enthalten ist, wird das längere ausgewertet. 2.3 Kommentare Es gibt zwei Arten von Kommentaren: Zeilenkommentare beginnen mit / / und erstrecken sich bis zum Ende der Zeile, in der sie stehen. Kommentarblöcke werden mit den beiden Zeichen /* eingeleitet und enden mit */. Sie können sich über mehrere Programmzeilen erstrecken. Kommentarblöcke können nicht geschachtelt werden. Allerdings haben innerhalb von Kommentarblöcken die Zeichen / / genauso wenig eine spezielle Bedeutung, wie umgekehrt die Zeichen /* und */ innerhalb von Zeilenkommentaren. In unserem Beispielprogramm sind je ein Zeilenkommentar und ein Kommentarblock enthalten. 2.4 Bezeichner Bezeichner sind Namen, die der Programmierer für die von ihm definierten Variablen, Konstanten, Typen, Klassen oder Funktionen wählt. In C++ können Bezeichner beliebig lang sein, d.h. alle Zeichen sind signifikant. Sie müssen mit einem Buchstaben oder dem Unterstrich _ beginnen. Daran anschließend sind kleine und große Buchstaben von abis z bzw. Abis Z, Ziffern von 0 bis 9 und Unterstriche erlaubt. Zwischen Groß- und Kleinschreibung wird unterschieden. prog-l enthält die Bezeichner main, hoehe, grundseite, flaeche und cout. 2.5 Schlüsselwörter 5 Bezeichner, die mit einem oder mehreren Unterstrichen beginnen, sollte man vermeiden, da sie typischerweise in C++-Bibliotheken verwendet werden. 2.5 Schlüsselwörter Die folgenden Schlüsselwörter sind in C++ reserviert und dürfen nicht anderweitig (z.B. als Bezeichner) benutzt werden: auto const else goto operator short template unsigned asm class double friend new return switch union break continue enum case default extern inline protected sizeof throw void if private signed this virtual catch delete float int public static try volatile char do for long register struct typedef while Die Schlüsselwörter catch, throw und try sind für die Ausnahmebehandlung (sog. "exception handling") reserviert, auf die wir im folgenden nicht eingehen, weil sie bei den von uns benutzten Compiler-Versionen noch nicht implementiert ist. Eine Art abgekürzter Schlüsselwörter sind die Interpunktionszeichen von C++: { < } > mit denen Anweisungen abgeschlossen oder in Blöcken zusammengefaßt werden, Listenelemente voneinander getrennt werden, etc. Das Beispielprogramm enthält die Schlüsselwörter int, double und return und die Interpunktionszeichen C, ), {, } und ;. Wie in prog-l treten geschweifte, runde oder spitze Klammern immer paarweise auf. 2.6 Operatoren In C++ steht eine Vielzahl von Operatoren zur Verfügung - das sind Symbole, die verschiedene Operationen auf ihren Argumenten, den sog. Operanden, ausführen: [] ->* %= % < « += > » & ?: <= «= * / >= »= 0 &= != + -> && 1= ++ 11 *= .* /= In prog-l wird beispielsweise mit dem Multiplikationsoperator * das Produkt von Höhe und Grundseite des Dreiecks berechnet und dieser Wert danach mit der Zahl 0.5 multipliziert. Mit dem Ausgabeoperator « werden dann der Text Flaeche 6 2. Lexikalische Konventionen des Dreiecks:, die berechnete Dreiecksfiäche und ein Zeilenendezeichen ausgegeben. Die Bedeutung der einzelnen Operatoren, ihre Wirkungsweise bei der Verarbeitung der Werte ihrer Operanden und der Berechnung des Werts von Ausdrücken, die sich aus Operatoren und Operanden zusammensetzen, werden in den folgenden Kapiteln, insbesondere in Abschnitt 6.2 erklärt. 2.7 Header-Dateien Die meisten in diesem Buch abgedruckten Beispielprogramme enthalten an ihrem Anfang eine oder mehrere Zeilen der Art #include <iostream.h> Dies ist eine Anweisung an den Compiler, vor dem eigentlichen Übersetzungsvorgang die entsprechende Zeile durch den gesamten Inhalt sog. Standard-Reader-Dateien, hier iostream. h, zu ersetzen. Standard-Reader-Dateien enthalten die Deklarationen von Funktionen, Typen, Klassen, usw., die strenggenommen nicht Bestandteil der Sprache C++ sind, aber bei jeder C++-Implementierung in der Standard bibliothek zur Verfügung gestellt werden. Um die Übersetzung von Programmen nicht grundlos aufwendig zu gestalten, wurden diese Deklarationen nach Funktionalität in verschiedene Reader-Dateien unterteilt. Z.B. befinden sich in iostream.h Deklarationen von Ein- und Ausgabefunktionen, in math. h Deklarationen von mathematischen Funktionen oder in time. h Deklarationen von Funktionen zur Manipulation von Datum und Uhrzeit. Standard-Reader stehen üblicherweise in einem Verzeichnis namens include oder unterhalb davon (bei den von uns verwendeten Compilern in den Verzeichnissen \borlandc\include bzw. /usr!include/CC). Wird der Name einer benötigten Reader-Datei wie oben - in < und> eingeschlossen - angegeben, so sucht der Compiler die Datei in diesem speziellen include-Verzeichnis. In den Abschnitten 14.17 und 14.18 werden wir zeigen, daß es bei der Programmierung von Klassen oft sinnvoll ist, die Spezifikation der Klasse (d.i. die Information, die ein Programm benötigt, das die Klasse benutzt) und die eigentliche Implementation der Klasse voneinander zu trennen, und die Klassenspezifikation in einer Reader-Datei abzulegen. In diesem Fall gibt man den Namen der Reader-Datei im Anwendungsprogramm in " und " eingeschlossen an, z.B. #include "DoubMenge.h" Der Compiler sucht die Datei dann zunächst im aktuellen Verzeichnis; falls er sie dort nicht findet, verfährt er, als sei #include <DoubMenge. h> angegeben. 2.7 Header-Dateien 7 Bemerkung Wie in Abschnitt 2.2 erwähnt, ist die Verwendung von Trennern bis auf die beschriebenen Ausnahmen option al. prog-l könnte man daher auch wie folgt eingeben: #include<iostream.h> int main(){int hoehe=3;int grundseite=5;double flaeche=hoehe* grundseite*O.5;cout«"Flaeche des Dreiecks: "«flaeche«'\n'; return O;} Es ist in das Ermessen des Programmierers gestellt, welche Form ihm geeignet und verständlich erscheint. Wir haben uns im folgenden an der Notation orientiert, die in Lippman (1991), Meyers (1992) oder Stroustrup (1991) benutzt wird. 3 Vordefinierte Datentypen Wie in den meisten Programmiersprachen gibt es in C++ vordefinierte - in die Sprache eingebaute - Datentypen und die entsprechenden Operatoren. Diese Typen, die die Grundlage aller vom Programmierer selbst abgeleiteten Typen sind, werden im folgenden Kapitel eingeführt. Die von einem Programm zu verarbeitenden Daten werden, wie auch der eigentliche Programmcode, im Speicher des Rechners als Bitfolgen abgelegt. Solche Speicherinhalte erhalten erst durch Angabe ihres Datentyps eine sinnvolle Interpretation. C++ stellt hierzu eine Reihe vordefinierter Datentypen zur Verfügung. Aus den vordefinierten Typen werden alle anderen in einem Programm verwendeten Datentypen abgeleitet. (Diese Typen werden in den Kapiteln 8, 11 und 14 besprochen.) Jedem Bezeichner muß genau ein Datentyp zugeordnet sein, der festlegt, welche Operationen für den Bezeichner definiert sind, wieviel Speicherplatz reserviert wird und welche Werte dem jeweiligen Speicherinhalt entsprechen. Mit dem Typ wird also auch ein Wertebereich, d.h. die Menge der Werte, die eine Variable, Konstante, etc. annehmen kann, festgelegt. Die vordefinierten Datentypen werden in arithmetische Typen und den Typ void unterteilt; ein arithmetischer Typ ist entweder ein ganzzahliger Datentyp oder ein Gleitpunkttyp. Zu den ganzzahligen Typen gehören char, short int, int, long int und die in Abschnitt 8.8 erläuterten Aufzählungstypen. Mit ihnen repräsentiert man ganze Zahlen verschiedener Größe sowie einzelne Zeichen. Der Datentyp char kann jedes Zeichen aus dem Zeichensatz der verwendeten C++Implementierung aufnehmen. Der in einem char gespeicherte Wert entspricht dabei der Ordinalzahl des Zeichens im jeweiligen Zeichensatz. In der Regel belegt er ein Byte. Das Schlüsselwort sizeof kann als einstelliger Operator verwendet werden und gibt dann die Größe eines Typs in Vielfachen des Typs char an. Per Definition ist daher sizeof(char) = 1. 10 3. Vordefinierte Datentypen Im Reference Manual wird garantiert, daß die folgenden Beziehungen von jeder Implementierung erfüllt werden: 1 = sizeof(char) ~ sizeof(short int) ~ sizeof(int) ~ sizeof(long int). Welche Wertebereiche tatsächlich realisiert sind, ist dem Standard-Reader limits.h zu entnehmen. Minimalanforderungen an einen C++-Compiler sind: char short int int long int o -32767 -32767 -2147483647 127 32767 32767 2147483647 Die beiden auf den Typnamen folgenden Zahlen geben hier jeweils die Unter- bzw. Obergrenze des Wertebereichs an, der mindestens zur Verfügung gestellt werden muß. Alle ganzzahligen Typen können explizit als signed bzw. unsigned deklariert werden. Somit lassen sich acht Kombinationen bilden: unsigned char unsigned short int unsigned int unsigned long int signed char signed short int signed int signed long int Wie die Namen bereits andeuten, steht unsigned für Typen ohne Vorzeichen, die nur positive Werte annehmen können und signed für Typen mit Vorzeichen, deren Werte auch negativ sein können. Wie das Vorzeichen behandelt wird, ist maschinenund implementationsabhängig - bei den beiden von uns verwendeten Compilern ist dafür jeweils das höchstwertige Bit reserviert. Damit unterscheidet sich ein unsigned Wertebereich von dem entsprechenden signed Wertebereich lediglich dadurch, daß er so verschoben wurde, daß er bei 0 beginnt und entsprechend größere Zahlen enthält. Bei jedem C++-Compiler ist sizeof(T) = sizeof(signed T) = sizeof(unsigned T), wobei Tfür char, short int, int oder long int steht. Wenn nichts angegeben ist, wird standardmäßig signed angenommen, d.h. int und signed int haben denselben Effekt - der Typ char bildet allerdings eine Ausnahme: hier ist es der jeweiligen Implementation überlassen, ob ein char als signed char oder unsigned char behandelt wird. 3. Vordefinierte Datentypen 11 Die Gleitpunkttypen in C++ sind float, double und long double. Ihre Wertebereiche sind jeweils eine Teilmenge der rationalen Zahlen. Ähnlich wie bei den ganzzahligen Typen ist garantiert, daß sizeof(float) :::; sizeof(double) :::; sizeof(long double) gilt. Details der verfügbaren Wertebereiche stehen in der Reader-Datei float. h. Jeder C++-Compiler muß jedoch mit den drei Gleitpunkttypen mindestens die rationalen Zahlen, deren Betrag zwischen 10-37 und 1037 liegt, darstellen können. Dabei müssen float- Werte mindestens 6, double- und long double-Werte mindestens 10 signifikante Dezimalziffern haben. Stehen beispielsweise im Speicher ab einer bestimmten Adresse die folgenden Bits 01000001 01000010 01000011 01000100 - aufsteigende Adressen und werden diese Bits als float-Wert interpretiert, so ist das Ergebnis beim Borland- bzw. AT&T-Compiler die Zahl 781.035217 bzw. 12.141422. Ein long int ergibt 1145258561 bzw. 1094861636, und bei Interpretation als vier chars erhält man jeweils A, B, C und D. Man sieht, daß beide Compiler zur Darstellung von Zeichen den ASCII-Code verwenden (American Standard Code for Information Interchange), der in Anhang A abgedruckt ist. Wie oben bemerkt, wird in einem char jeweils die Ordinalzahl des entsprechenden Zeichens gespeichert, im Beispiel also 65 für A, 66 für B, etc. Die unterschiedlichen Ergebnisse bei den arithmetischen Typen kommen dadurch zustande, daß zusammengehörige Bytes von den verwendeten Prozessoren in umgekehrter Reihenfolge aneinandergefügt werden. Der vordefinierte Datentyp void bezeichnet eine leere Wertemenge. Wir werden ihn im folgenden als Typ des Funktionswerts bei Funktionen verwenden, die keinen Wert zurückgeben. Variablen vom Typ void sind aus naheliegenden Gründen nicht zulässig. void - und insbesondere der abgeleitete Typ Zeiger auf void wurde bei früheren Compiler-Versionen zur Definition von Funktionen mit variablen Argumenttypen oder Klassen mit variablen Elementtypen verwendet. Mit der Verfügbarkeit sog. parametrisierter Funktionen und Klassen (vgl. Kapitel 18) sind derartige Konstruktionen nicht mehr interessant. Bemerkung Der Vollständigkeit halber, und zum Verständnis der Programme anderer Entwickler, muß an dieser Stelle erwähnt werden, daß das Schlüsselwort int im Zusammenhang mit anderen Schlüsselwörtern, wie unsigned, short, const, etc. entfallen kann. Z.B. kann anstelle von unsigned int kurz unsigned stehen. Diese Kurznotation wird von uns im folgenden nicht verwendet werden. 4 Literalkonstanten In Abschnitt 2.2 wurde erklärt, daß die Symbolfolge, aus der sich ein C++-Programm zusammensetzt, Literalkonstanten enthalten kann. Diese beschreiben einen Wert, der sich während der Laufzeit des Programms nicht ändern kann. Sie heißen Literalkonstanten, weil ihr Wert bereits durch die Schreibweise der Konstanten ausgedrückt wird. Jede Literalkonstante hat einen zugehörigen Datentyp. Entsprechend den vordefinierten' Datentypen gibt es ganzzahlige Konstanten und Zeichenkonstanten sowie Gleitpunktkonstanten. Zur einfachen Ausgabe mehrerer Zeichen stehen darüber hinaus Zeichenketten zur Verfügung. Der Compiler erkennt nicht nur den Wert sondern auch den Typ einer Literalkonstanten jeweils ohne besondere Deklaration. 4.1 Ganzzahlige Konstanten Zur Darstellung ganzzahliger Konstanten kann das Dezimal-, Oktal- oder Hexadezimalsystem benutzt werden. In der Dezimaldarstellung besteht eine ganzzahlige Konstante aus einer Ziffernfolge, die nicht mit 0 beginnen darf. Liegt ihr Wert im Wertebereich int, so hat sie den Typ int, anderenfalls den Typ lang int, bzw. unsigned lang int. (Ihr Typ ist somit maschinen- und implementationsabhängig.) Beginnt eine ganzzahlige Konstante mit der Ziffer 0, so wird sie als Oktalzahl interpretiert, sie muß also aus Oktalziffern bestehen; beginnt die Konstante mit Ox oder OX, wird sie als Hexadezimalzahl interpretiert und die nachfolgenden Ziffern müssen Hexadezimalziffern sein: OktalzijJer: eins von o 1 2 3 4 5 6 7 ZijJer: eins von OktalzijJer 8 9 HexadezimalzijJer: eins von ZijJer a A b B c C d D e E f F Je nach Größe ihres Werts hat die Konstante den Typ int, unsigned int, lang