C++ fur Naturwissenschaftler . Beispielorientierte Einfuhrung 382731531X, 9783827315311 [PDF]


161 70 2MB

German Pages 485 Year 2000

Report DMCA / Copyright

DOWNLOAD PDF FILE

Table of contents :
C++ für Naturwissenschaftler......Page 2
Abgeleitete Datentypen......Page 4
Funktionen......Page 5
Vererbung......Page 6
Datentypen der STL......Page 7
Numerik-Programme......Page 8
Index......Page 9
Was ist OOP?......Page 14
Warum C++?......Page 18
Die Entwicklung von C++......Page 19
Die Weiterentwicklung von C......Page 22
Java als C++-Derivat......Page 23
Der Borland C++-Compiler (Version 5.02)......Page 28
Der Microsoft Visual C++-Compiler......Page 30
Der Inprise C++ Builder......Page 31
Der GNU C++-Compiler......Page 33
Syntax-Fehler......Page 34
Rundungsfehler......Page 35
Einfache Algorithmen......Page 36
Umwandlung einer Dezimalzahl ins Binärsystem......Page 37
Euklidscher Algorithmus......Page 38
Schnelles Potenzieren......Page 39
Übungen......Page 40
Zeichensatz......Page 42
Schlüsselwörter......Page 44
Operatoren......Page 45
Literale Konstanten......Page 47
Definition und Deklaration......Page 48
Einfache Datentypen......Page 49
Der Aufzählungstyp enum......Page 54
Speicherklassen......Page 55
Zeiger......Page 60
Erzeugen dynamischer Variablen......Page 63
Referenzen......Page 65
Typumwandlungen......Page 66
Reihungen......Page 67
Der struct- Typ......Page 69
C-Strings......Page 73
C++-Strings......Page 75
Übungen......Page 76
Arithmetische Ausdrücke......Page 78
Logische Operatoren......Page 79
Bitoperatoren......Page 83
Zuweisungen......Page 86
Weitere Operatoren......Page 88
Grenzen der Zahlbereiche......Page 90
Typumwandlungen......Page 91
Der Namensraum......Page 93
Übungen......Page 96
Verbundanweisung......Page 98
Bedingte Anweisungen......Page 99
Die FOR-Schleife......Page 101
Die WHILE-Schleife......Page 102
Die DO-Schleife......Page 103
Die Transfer-Funktionen......Page 104
Das assert()-Makro......Page 105
Übungen......Page 106
Deklaration und Definition......Page 110
Mathematische Standardfunktionen......Page 112
Selbst definierte Funktionen......Page 116
C-String-Funktionen......Page 117
C++-String-Funktionen......Page 119
Char-Funktionen......Page 120
Rekursive Funktionen......Page 121
Die Funktion main()......Page 123
Funktion mit variabler Parameterliste......Page 125
Call-by-value......Page 126
Call-by-reference......Page 127
Zeiger auf Funktionen......Page 129
Array von Funktionszeigern......Page 131
Funktionen, die einen Zeiger liefern......Page 132
Funktionen, die eine Referenz liefern......Page 133
Default-Argumente......Page 134
Überladen von Funktionen......Page 135
Template-Funktionen......Page 136
Übungen......Page 138
Klassen als ADT......Page 142
Definition und Deklaration......Page 144
Elementfunktionen......Page 146
Eine Klasse Bruch......Page 148
Konstruktoren......Page 149
Destruktoren......Page 154
Beispiel zur Datenkapselung......Page 156
Klasse mit Array......Page 158
Statische Datenelemente......Page 161
Überladen der arithmetischen Operatoren......Page 163
Überladen des Inkrement-Operators......Page 165
Benutzerdefinierte Typumwandlung......Page 166
Überladen des Operators []......Page 167
Überladen des Operators ()......Page 168
Explizites Überladen des Operators =......Page 169
Friend-Funktionen......Page 170
Der this-Zeiger......Page 173
Klasse mit Funktionszeiger......Page 174
Klasse mit Invarianten......Page 176
Friend-Klassen......Page 177
Beispiel aus der Analytischen Geometrie......Page 178
Übungen......Page 180
Semantik von Zuweisungen......Page 182
Semantik von IF-Anweisungen......Page 183
Semantik von WHILE-Anweisungen......Page 184
Die Metrik von McCabe......Page 187
Die Metrik von Halstead......Page 188
Der Wartbarkeitsindex......Page 190
Was ist die UML?......Page 191
Das objektorientierte Paradigma......Page 192
Wichtige Diagramme......Page 193
Das Klassendiagramm......Page 194
Das Aktivitätsdiagramm......Page 196
Das Anwendungsfalldiagramm......Page 197
Kriterien für Programmiersprachen......Page 198
Forderungen des Software-Engineerings......Page 201
Ablauf eines Ausnahmefalls......Page 204
Ein Beispiel mit selbst definierten Fehlerklassen......Page 206
Die Funktion uncaught_exception()......Page 207
Selbst definierte Handler......Page 208
Die Standardausnahmen......Page 209
Vererbung......Page 210
Zugriffsmöglichkeiten......Page 211
Konstruktoren und Destruktoren......Page 213
Polymorphismus......Page 216
Virtuelle Funktionen......Page 217
RTTI......Page 219
Abstrakte Basisklassen......Page 224
Beispiel aus der Biologie......Page 227
Beispiel aus der Mathematik......Page 229
Mehrfache Vererbung......Page 231
Virtuelle Basisklassen......Page 234
Übung......Page 236
Die Basisklasse basic_ios......Page 242
Ausgabe......Page 243
Manipulatoren......Page 248
Eingabe......Page 251
Die Statusfunktionen......Page 254
Internationalisierung......Page 256
Dateibehandlung......Page 258
Binärdateien......Page 259
Textdateien......Page 261
Relationen zwischen Klassen......Page 264
Die Aggregation......Page 265
Die Komposition......Page 267
Die Uses-A-Relation......Page 268
Wechselseitig enthaltende Objekte......Page 270
Die Vererbung......Page 272
Verschachtelte Klassen......Page 273
Klassen......Page 276
Template-Klasse Queue......Page 277
Template-Klasse Stack......Page 279
Template-Klasse Polynom......Page 281
Template-Klasse Binärbaum......Page 284
Numerische Parameterwerte......Page 286
Datentypen der STL......Page 290
Iteratoren......Page 291
Funktionsobjekte......Page 293
Adapter für Funktionszeiger......Page 294
Prädikate und Vergleiche......Page 295
Projektionen......Page 298
Negativierer......Page 299
Hilfsmittel......Page 300
Der Container vector......Page 301
Der Container deque......Page 304
Der Container list......Page 306
Der Container map......Page 308
Der Container multimap......Page 310
Der Container set......Page 312
Der Container multiset......Page 317
Der Adapter stack......Page 318
Der Adapter queue......Page 319
Der Adapter priority_queue......Page 320
Die Klasse bitset......Page 322
Die Klasse string......Page 324
Die Klasse valarray......Page 325
Übungen......Page 328
for_each()......Page 330
count()-Funktion......Page 331
Die mismatch()-Funktion......Page 332
Die copy()-Funktion......Page 333
Die swap()-Funktionen......Page 334
Die transform()-Funktion......Page 335
Die replace()-Funktion......Page 336
Die generate()-Funktion......Page 337
Die unique-Funktion......Page 338
Die reverse()-Funktion......Page 340
Die rotate()-Funktion......Page 341
find()-Funktion......Page 343
Die search()-Funktion......Page 345
Die binary_search()-Funktion......Page 347
Die equal_range()-Funktionen......Page 348
Sortierähnliche Verfahren......Page 349
Die stable_sort()-Funktion......Page 350
Die partial_sort()-Funktion......Page 351
Die nth_element-Funktion......Page 352
Die Funktion partition()......Page 353
Die merge()-Funktion......Page 354
Die inplace_merge()-Funktion......Page 355
Die Mengen-Funktionen......Page 356
Die min()/max()-Funktion......Page 358
Permutationen......Page 359
Die next_permutation()-Funktion......Page 360
Die prev_permuation()-Funktion......Page 361
Zufallspermutationen......Page 362
Heap-Algorithmen......Page 364
Komplexe Arithmetik......Page 365
Die inner_product()-Funktion......Page 370
Die partial_sum()-Funktion......Page 371
Lineare Regression......Page 373
Exponentielle Regression......Page 376
Geometrische Regression......Page 377
Ein Beispiel zu X Windows......Page 380
Grafik mit dem C++Builder......Page 382
Hofstadter-Schmetterling......Page 384
Der Ikeda-Attraktor......Page 386
Julia-Menge......Page 388
Orthogonale Trajektorien......Page 390
Die Binomialverteilung......Page 394
Die Poisson-Verteilung......Page 396
Hypergeometrische Verteilung......Page 398
Normalverteilung......Page 400
Die t- Verteilung......Page 402
Die x²-Verteilung......Page 406
F-Verteilung......Page 408
Eintauchtiefe einer Kugel......Page 412
Arbeitspunkt einer Diode......Page 416
Die Richmond-Iteration......Page 418
Numerische Differenziation......Page 420
Adaptive Simpson-Formel......Page 422
Integration nach Gauss......Page 424
Integration von Tabellenfunktionen......Page 426
Romberg-Integration......Page 429
Runge-Kutta-Fehlberg......Page 432
Verfahren von Dormand-Prince......Page 434
Adams-Moulton- Verfahren......Page 436
Tschebyschew-Approximation......Page 439
Gleichgewichtstemperatur der Erde......Page 444
Energieanteil eines schwarzen Strahlers......Page 448
Abkühlvorgang eines Festkörpers......Page 451
Die Lorenz-Gleichungen......Page 452
Massenformel von Weizsäcker......Page 454
Das Drei-Körper-Problem......Page 458
Dampfdruckkurve......Page 462
Biegeschwingung eines einseitig eingespannten Stabs......Page 466
Zustandsgrößen eines Sterns......Page 468
UML......Page 474
Mathematik......Page 475
B......Page 476
D......Page 477
G......Page 478
K......Page 479
M......Page 480
P......Page 481
S......Page 482
U......Page 483
Z......Page 484
Papiere empfehlen

C++ fur Naturwissenschaftler . Beispielorientierte Einfuhrung
 382731531X, 9783827315311 [PDF]

  • 0 0 0
  • Gefällt Ihnen dieses papier und der download? Sie können Ihre eigene PDF-Datei in wenigen Minuten kostenlos online veröffentlichen! Anmelden
Datei wird geladen, bitte warten...
Zitiervorschau

Dietmar Herrmann

C++ für Naturwissenschaftler Beispielorientierte Einführung

Bitte beachten Sie: Der originalen Printversion liegt eine CD-ROM bei. In der vorliegenden elektronischen Version ist die Lieferung einer CD-ROM nicht enthalten. Alle Hinweise und alle Verweise auf die CD-ROM sind ungültig.

An imprint of Pearson Education Deutschland GmbH München • Boston • San Francisco • Harlow, England Don Mills, Ontario • Sydney • Mexico City Madrid • Amsterdam

Ein Titeldatensatz für diese Publikation ist bei Der Deutschen Bibliothek erhältlich.

Die Informationen in diesem Produkt werden ohne Rücksicht auf einen eventuellen Patentschutz veröffentlicht. Warennamen werden ohne Gewährleistung der freien Verwendbarkeit benutzt. Bei der Zusammenstellung von Texten und Abbildungen wurde mit größter Sorgfalt vorgegangen. Trotzdem können Fehler nicht vollständig ausgeschlossen werden. Verlag, Herausgeber und Autoren können für fehlerhafte Angaben und deren Folgen weder eine juristische Verantwortung noch irgendeine Haftung übernehmen. Für Verbesserungsvorschläge und Hinweise auf Fehler sind Verlag und Herausgeber dankbar. Alle Rechte vorbehalten, auch die der fotomechanischen Wiedergabe und der Speicherung in elektronischen Medien. Die gewerbliche Nutzung der in diesem Produkt gezeigten Modelle und Arbeiten ist nicht zulässig. Fast alle Hardware- und Softwarebezeichnungen, die in diesem Buch erwähnt werden, sind gleichzeitig auch eingetragene Warenzeichen oder sollten als solche betrachtet werden. Umwelthinweis: Dieses Buch wurde auf chlorfrei gebleichtem Papier gedruckt. Die Einschrumpffolie – zum Schutz vor Verschmutzung – ist aus umweltverträglichem und recyclingfähigem PE-Material.

10 9 8 7 6 5 4 3 2 1 04 03 02 01

ISBN 3-8273-1531-X © 2001 by Prentice Hall, ein Imprint der Pearson Education Deutschland GmbH, Martin-Kollar-Straße 10–12, D-81829 München/Germany Alle Rechte vorbehalten Einbandgestaltung: Hommer Design Production, Haar bei München Lektorat: Irmgard Wagner, Taufkirchen, [email protected] Korrektorat: Petra Kienle, Fürstenfeldbruck Herstellung: TYPisch Müller, Arcevia, Italien, [email protected] Satz: reemers publishing services gmbh, Krefeld Druck und Verarbeitung: Media Print, Paderborn Printed in Germany

Inhaltsverzeichnis Vorwort

11

1 Einleitung

15

1.1 1.2 1.3 1.4 1.5

Was ist OOP? Warum C++? Die Entwicklung von C++ Die Weiterentwicklung von C Java als C++-Derivat

2 Algorithmen und Compiler 2.1 2.2 2.3 2.4

Wie man ein C++-Programm compiliert Programmfehler Einfache Algorithmen Übungen

3 Lexikalische Elemente und Datentypen 3.1 3.2 3.3 3.4 3.5 3.6 3.7 3.8 3.9

Zeichensatz Schlüsselwörter Kommentare und Separatoren Operatoren Literale Konstanten Definition und Deklaration Einfache Datentypen Der Aufzählungstyp enum Speicherklassen

4 Abgeleitete Datentypen 4.1 4.2 4.3 4.4 4.5 4.6 4.7 4.8 4.9

Konstanten Zeiger Erzeugen dynamischer Variablen Referenzen Typumwandlungen Reihungen Der struct-Typ Strings Übungen

15 19 20 23 24

29 29 35 37 41

43 43 45 46 46 48 49 50 55 56

61 61 61 64 66 67 68 70 74 77

6

Inhaltsverzeichnis

5 Ausdrücke und Anweisungen 5.1 5.2 5.3 5.4 5.5 5.6 5.7 5.8 5.9 5.10

Arithmetische Ausdrücke Logische Operatoren Bitoperatoren Zuweisungen Weitere Operatoren Grenzen der Zahlbereiche Typumwandlungen Anweisungen Der Namensraum Übungen

6 Kontrollstrukturen 6.1 6.2 6.3 6.4 6.5 6.6

Verbundanweisung Bedingte Anweisungen Wiederholungsanweisungen Die Transfer-Funktionen Das assert()-Makro Übungen

7 Funktionen 7.1 7.2 7.3 7.4 7.5 7.6 7.7 7.8 7.9 7.10 7.11 7.12 7.13 7.14 7.15 7.16 7.17 7.18 7.19

Deklaration und Definition Mathematische Standardfunktionen Selbst definierte Funktionen String-Funktionen Char-Funktionen Rekursive Funktionen Die Funktion main() Funktion mit variabler Parameterliste Call-by-value Call-by-reference Zeiger auf Funktionen Array von Funktionszeigern Funktionen, die einen Zeiger liefern Funktionen, die eine Referenz liefern Default-Argumente Inline-Funktionen Überladen von Funktionen Template-Funktionen Übungen

79 79 80 84 87 89 91 92 94 94 97

99 99 100 102 105 106 107

111 111 113 117 118 121 122 124 126 127 128 130 132 133 134 135 136 136 137 139

Inhaltsverzeichnis

7

8 Klassen

143

8.1 8.2 8.3 8.4 8.5 8.6 8.7 8.8 8.9 8.10 8.11 8.12 8.13 8.14 8.15 8.16 8.17 8.18 8.19

143 145 147 149 149 150 155 157 159 162 162 164 168 171 174 175 177 178 181

Klassen als ADT Definition und Deklaration Elementfunktionen Klasse als Verallgemeinerung der Funktion Eine Klasse Bruch Konstruktoren Destruktoren Beispiel zur Datenkapselung Klasse mit Array Klasse mit dynamischem Array Statische Datenelemente Überladen von Operatoren Überladen von Operatoren 2 Friend-Funktionen Der this-Zeiger Klasse mit Funktionszeiger Klasse mit Invarianten Friend-Klassen Übungen

9 Elemente des Software-Engineerings 9.1 9.2 9.3 9.4 9.5

Die Verifikation von Algorithmen Software-Metrik Stichpunkte der UML Kriterien für Programmiersprachen Forderungen des Software-Engineerings

10 Ausnahmebehandlung 10.1 10.2 10.3 10.4

Ablauf eines Ausnahmefalls Ein Beispiel mit selbst definierten Fehlerklassen Vordefinierte Fehlerfunktionen Die Standardausnahmen

11 Vererbung 11.1 11.2 11.3 11.4 11.5 11.6

Zugriffsmöglichkeiten Konstruktoren und Destruktoren Polymorphismus Virtuelle Funktionen RTTI Abstrakte Basisklassen

183 183 188 192 199 202

205 205 207 208 210

211 212 214 217 218 220 225

8

Inhaltsverzeichnis

11.7 11.8 11.9 11.10 11.11

Beispiel aus der Biologie Beispiel aus der Mathematik Mehrfache Vererbung Virtuelle Basisklassen Übung

12 Ein-/Ausgabestrom 12.1 12.2 12.3 12.4 12.5 12.6 12.7 12.8

Die Basisklasse basic_ios Ausgabe Manipulatoren Eingabe Die Statusfunktionen Streams für Zeichenketten Internationalisierung Dateibehandlung

13 Relationen zwischen Klassen 13.1 13.2 13.3 13.4 13.5 13.6

Die Aggregation Die Komposition Die Uses-A-Relation Wechselseitig enthaltende Objekte Die Vererbung Verschachtelte Klassen

14 Template-Klassen 14.1 14.2 14.3 14.4 14.5

Template-Klasse Queue Template-Klasse Stack Template-Klasse Polynom Template-Klasse Binärbaum Numerische Parameterwerte

15 Datentypen der STL 15.1 15.2 15.3 15.4 15.5 15.6 15.7 15.8 15.9 15.10

Iteratoren Funktionsobjekte Hilfsmittel Der Container vector Der Container deque Der Container list Der Container map Der Container multimap Der Container set Der Container multiset

228 230 232 235 237

243 243 244 249 252 255 257 257 259

265 266 268 269 271 273 274

277 278 280 282 285 287

291 292 294 301 302 305 307 309 311 313 318

Inhaltsverzeichnis

15.11 15.12 15.13 15.14 15.15 15.16 15.17

Der Adapter stack Der Adapter queue Der Adapter priority_queue Die Klasse bitset Die Klasse string Die Klasse valarray Übungen

16 Algorithmen der STL 16.1 16.2 16.3 16.4 16.5 16.6 16.7 16.8 16.9 16.10 16.11 16.12

Nichtmodifizierende Algorithmen Modifizierende Algorithmen Suchen in geordneten Bereichen Sortierähnliche Verfahren Misch-Verfahren Die Mengen-Funktionen Minumum und Maximum Permutationen Heap-Algorithmen Komplexe Arithmetik Numerische Algorithmen Demoprogramme zu den STL Algorithmen

17 Grafik 17.1 17.2 17.3 17.4 17.5 17.6

Ein Beispiel zu X Windows Grafik mit dem C++Builder Hofstadter-Schmetterling Der Ikeda-Attraktor Julia-Menge Orthogonale Trajektorien

Die Binomialverteilung Die Poisson-Verteilung Hypergeometrische Verteilung Normalverteilung Die t-Verteilung Die c2-Verteilung F-Verteilung

19 Numerik-Programme 19.1 19.2

319 320 321 323 325 326 329

331 331 334 348 350 355 357 359 360 365 366 371 374

381

18 Statistik-Programme 18.1 18.2 18.3 18.4 18.5 18.6 18.7

9

Eintauchtiefe einer Kugel Arbeitspunkt einer Diode

381 383 385 387 389 391

395 395 397 399 401 403 407 409

413 413 417

10

Inhaltsverzeichnis

19.3 19.4 19.5 19.6 19.7 19.8 19.9 19.10 19.11 19.12

Die Richmond-Iteration Numerische Differenziation Adaptive Simpson-Formel Integration nach Gauss Integration von Tabellenfunktionen Romberg-Integration Runge-Kutta-Fehlberg Verfahren von Dormand-Prince Adams-Moulton-Verfahren Tschebyschew-Approximation

20 Physik-Programme 20.1 20.2 20.3 20.4 20.5 20.6 20.7 20.8 20.9

Gleichgewichtstemperatur der Erde Energieanteil eines schwarzen Strahlers Abkühlvorgang eines Festkörpers Die Lorenz-Gleichungen Massenformel von Weizsäcker Das Drei-Körper-Problem Dampfdruckkurve Biegeschwingung eines einseitig eingespannten Stabs Zustandsgrößen eines Sterns

21 Literaturverzeichnis C++ Programmiersprachen UML Informatik Astronomie Physik Chaostheorie Mathematik

Index

419 421 423 425 427 430 433 435 437 440

445 445 449 452 453 455 459 463 467 469

475 475 475 475 476 476 476 476 476

477

Vorwort

C++ ist ohne Zweifel die Programmiersprache der neunziger Jahre. Die Gründe für den Erfolg von C++ sind unter anderem: 왘 C++ weist die wesentlichen Merkmale einer objektorientierten Programmierspra-

che auf, erlaubt aber dem Anwender einen Übergang von der prozeduralen zur objektorientierten Programmierweise. 왘 Compiler für C++ sind praktisch an allen Maschinen verfügbar; der Sprachstan-

dard garantiert eine sichere Investition in C++. 왘 C++-Programme sind mit einer Vielzahl von existierenden C-Quellcodes kombi-

nierbar. Außerdem gibt es zahlreiche C++-Bibliotheken für nahezu alle Anwendungen. 왘 C++ ist Ausgangspunkt für die Entwicklung weiterer objektorientierter Program-

miersprachen wie Java. Das Erlernen von C++ liefert eine fundierte Kenntnis der erfolgreichsten Familie von Programmiersprachen, die zur Zeit durch die neue Programmiersprache C# von Microsoft erweitert wird. Viele Bücher über C++ handeln von irgendwelchen abstrakten Klassen oder widmen sich allgemein der objektorientierten Softwareerstellung. Was fehlt, ist eine Darstellung, die das objektorientierte Programmmieren (OOP) aus der Sicht des Naturwissenschaftlers aufzeigt. Hier setzt das vorliegende Buch ein. Es zeigt für Leser mit Grundkenntnissen im Programmieren: 왘 wie die strukturierte und prozedurale Programmierung objektorientiert wird, 왘 wie vielfältig Klassen im naturwissenschaftlichen Bereich eingesetzt werden kön-

nen. Da C++ eine der mächtigsten Programmiersprachen ist, ist sie nicht, wie andere Programmiersprachen, in wenigen Stunden erlernbar. Um den Lernvorgang zu erleichtern, wird die Leserin bzw. der Leser durch konkrete, nachvollziehbare Beispiele und zahlreiche Abbildungen, aber nicht durch abstrakt-formale Beschreibungen in die komplexe Welt der C++-Programmierung eingeführt.

12

Vorwort

Die Grundlage dieses Buchs bildet die Beschreibung von C++ gemäß der ANSI/ISO C++-Norm, die im Juli 1998 von der internationalen Behörde ISO/IEC akzeptiert worden ist. Es ist zu erwarten, dass künftige Compilerversionen weitgehend mit der Norm konform gehen. Um die Bandbreite der C++-Anwendungen zu demonstrieren, behandelt das Buch eine Vielzahl von Themen aus Mathematik, Informatik, Physik, Astronomie und Computergrafik. Es ist natürlich im Rahmen eine solchen Buchs nicht möglich, alle benötigten Grundlagen aus diesen Wissenschaften bereitzustellen. Der Leser wird hier auf die Fachliteratur (im Anhang) verwiesen. Kapitel 1 enthält als Einführung die Geschichte und Entwicklung der Programmiersprache C++ und das Basiswissen über OOP. Kapitel 2 bietet grundlegende Informationen über das Arbeiten mit C++-Compilern, über auftretende Fehlermeldungen und erläutert die Eigenschaften von Algorithmen. Kapitel 3 stellt die Syntax von C++ und die einfachen Datentypen so ausführlich dar, dass das Buch auch ohne C-Kenntnisse gelesen werden kann. Kapitel 4 erläutert alle abgeleiteten Datentypen wie Pointer, Referenzen, dynamische Variablen und Reihungen (Array). Kapitel 5 erklärt die vielfältigen Operatoren, Ausdrücke und Anweisungen sowie den Begriff des Namensraums. Kapitel 6 diskutiert die Kontrollstrukturen; d.h. bedingte Anweisungen, Wiederholungsanweisungen und Transferfunktionen. Kapitel 7 zeigt alles über Funktionen, Rekursivität, Wertübergabe, Default-Argumente, Inline- und Template-Funktionen. Kapitel 8 liefert die Grundlagen für das Programmieren von Klassen, Konstruktoren, Destruktoren, statischen Elementen, Überladen von Operatoren, Funktionszeigern und Friend-Klassen. Kapitel 9 vermittelt einen Einblick in Methoden des Software-Engineerings. Hier findet sich auch eine Einführung in die Unified Modeling Language (UML), die in Zukunft noch größere Bedeutung erlangen wird. Exemplarisch werden die KlassenDiagramme behandelt, die mit Hilfe der UML-Software »Together 4.0« erstellt wurden. Kapitel 10 zeigt die Grundzüge der in C++ eingebauten Ausnahmebehandlung. Kapitel 11 ist der einfachen und mehrfachen Vererbung gewidmet. Es werden die Zugriffsmöglichkeiten der abgeleiteten Klassen, virtuelle Funktionen und abstrakte Basisklassen diskutiert. Kapitel 12 vermittelt die Grundlagen der objektorientierten Ein- und Ausgabe. Kapitel 13 erörtert die vielfältigen Beziehungen von Klassen untereinander, insbesondere das Aggregat und die Komposition. Kapitel 14 erklärt die Programmierung von Template-Klassen an Hand der Datenstrukturen Stack, Warteschlange (Queue) und Polynom. Die Beschäftigung mit diesen Template-Klassen dient als Vorbereitung zum Arbeiten mit der Standard Template Library (STL).

Vorwort

13

Kapitel 15 beschäftigt sich ausführlich mit den generischen Datentypen (Containern) vector, deque, list, map, set und den Adaptern stack, priority_queue und queue. Kapitel 16 stellt umfassend dar, wie die Algorithmen der STL auf den generischen Datentypen der STL operieren können. Durch viele Beispiele wird das Arbeiten mit der Template-Klasse der komplexen Zahlen erläutert. Kapitel 17 liefert einige interessante grafische Anwendungen aus dem Bereich der Chaostheorie, fraktalen Geometrie und der komplexen Abbildungen. Gezeigt wird u. a. eine Julia-Menge und der bekannte Schmetterling von Hofstadter, der die fraktalen Eigenwerte von Bloch-Zellen im homogenen Magnetfeld mit Cantor-Eigenschaften grafisch demonstriert. Kapitel 18 bietet grundlegende Klassen zur Berechnung von Wahrscheinlichkeitsverteilungen und Prüfstatistiken. Kapitel 19 enthält wichtige Klassen zur Lösung von nichtlinearen Gleichungen, numerischer Integration von Integralen und gewöhnlichen Differentialgleichungen. Dabei werden auch neuere und weniger bekannte Algorithmen wie die Integration nach Dormand-Prince, die Richmond-Iteration und die adaptive Simpson-Integration behandelt. Das abschließende Kapitel 20 löst interessante physikalische Problemstellungen, u. a. die Gleichgewichtstemperatur der Erde, Lorenz-Gleichungen, Wärmestrahlung, Dampfdruckkurve, Eigenwertproblem eines eingespannten Stabs und das eingeschränkte Drei-Körper-Problem. Beiliegende CD-ROM enthält alle Musterlösungen der Übungsaufgaben und den Quellcode der im Buch enthaltenen nichttrivialen Programme. Damit Sie die CD-ROM nützen können, müssen Sie über ein entsprechendes Laufwerk verfügen. Der Quellcode der Programme kann mit allen Betriebssystemen wie Windows 95/98/NT, Linux, Solaris oder Apple gelesen werden. Zum Compilieren der C++-Programme wird ein neuerer C++-Compiler benötigt; ausführliche Hinweise zum Arbeiten mit Compilern finden sich zweiten Kapitel. Leser, die über eine Internet-Zugang verfügen, können sich den Borland-Compiler (Version 5.5) in der Kommandozeilenversion downloaden. Ebenfalls kostenlos im Internet verfügbar ist der GNU-C++-Compiler; er wird für alle Rechner mit dem Linux-Betriebsystem empfohlen. Es wird ausdrücklich darauf hingewiesen, dass es derzeit keinen Compiler gibt, der alle im Buch enthaltenen Programme compilieren kann; viele Compiler haben noch nicht alle Neuerungen der C++-Norm implementiert. Dem Verlag Addison-Wesley, nunmehr Teil des Verlags Pearson Education, danke ich für die Herausgabe der zweiten, wesentlich erweiterten Auflage dieses Buch im Rahmen der Serie Scientific Computing. Dadurch war es möglich, die gesamte Darstellung der neuen ISO C++-Norm anzupassen und den Umfang durch ca. 150 Seiten zur Standard Template Library erheblich zu steigern. Besonderen Dank schulde ich Frau Irmgard Wagner, die als Lektorin einen großen Verdienst an dem Zustandekommen des Buchprojekts hat und Frau Petra Kienle für das Korrekturlesen des Buches.

14

Vorwort

Danken möchte ich auch allen, die per E-Mail und Brief geholfen haben, Druckfehler publik zu machen, insbesondere Herrn Tiebel (Uni Potsdam), Herrn Lüer (Uni Hannover), Herrn Braeske (Uni Erlangen) und Herrn Mende (Bochum). Für Hinweise und (humorvolle) Kommentare ist der Autor dankbar. Er ist erreichbar unter der E-Mail-Adresse [email protected]. Dietmar Herrmann, Oktober 2000

1

Einleitung No turning back. Object-orientation is the future, and the future is here and now. E. Yourdon

Object-oriented programming is an exceptionally bad idea which could only have originated in California. E.W. Dijkstra

1.1

Was ist OOP?

Das objektorientierte Programmieren (abgekürzt OOP) ist nur eine von mehreren Programmiermethoden, die in der Informatik seit der Einführung von FORTRAN entwickelt worden sind. 왘 Der prozedurale Programmierstil ist durch die Programmiersprachen FORTRAN

und ALGOL eingeführt worden und dient hauptsächlich dem Rechnen im technisch-naturwissenschaftlichen Bereich. Ein Programm besteht hier also aus einer bestimmten Zahl von Funktionen und Prozeduren. Ein Algorithmus sorgt dafür, dass diese Funktionen in geeigneter Weise abgearbeitet werden. Bekannte prozedurale Programmiersprachen sind Pascal und C. 왘 Der deklarative Programmierstil wird insbesondere durch die Programmiersprache

PROLOG vertreten. Ein deklaratives Programm besteht aus Fakten und logischen Regeln. Es wird nicht durch einen vorgegebenen Algorithmus gesteuert. Vielmehr versucht der Interpreter bzw. Compiler mit Hilfe des eingebauten Backtracking, eine oder mehrere Lösungen zu finden, die die Wissensbasis und Regeln erfüllen. Dieser Programmierstil ist sehr gut geeignet für die Implementierung von Expertensystemen. 왘 In der funktionalen Programmierung werden, meist mit Hilfe von Rekursion, benut-

zerdefinierte Funktionen auf einfache Listenoperationen zurückgeführt. Da rekursiv definierte Strukturen stets mit Hilfe von mathematischer Induktion charakterisiert werden können, eignen sich besonders mathematische Strukturen und Symbolverarbeitung zur funktionalen Programmierung. Ein Vertreter dieser Richtung ist das bereits Ende der fünfziger Jahre entstandene LISP. Die meisten der Computer-Algebra-Systeme von MUMATH bis MATHEMATICA besitzen einen eingebauten LISP-Interpreter, der die eingegebenen Terme symbolisch abarbeitet. 왘 Die objektorientierte Programmierung trennt nicht mehr Algorithmus und Daten-

struktur, sondern modelliert die Problemstellung durch interagierende Objekte, die bestimmter eingebauter Methoden fähig sind. Alle Aktivitäten gehen dabei von diesen Objekten aus, die wiederum andere Objekte durch Aussenden von geeigne-

16

1 Einleitung

ten Botschaften (messages) zu Aktionen bzw. Interaktionen auffordern. Objekte mit gleichem Verhalten werden in sog. Klassen definiert. Mit Hilfe solcher Objekte können komplexe Modelle der realen Welt nachgebildet werden; die eingesetzten Objekte lassen sich bausteinartig für ähnliche Probleme wiederverwenden (Modularität). Das Konzept der Klassen wurde von der Programmiersprache SIMULA 76 übernommen. Als erste rein objektorientierte Programmiersprache gilt SMALLTALK (1980). Die Programmiersprache C++ ist eine hybride Sprache, da sie neben der Objektorientierung aus Effizienzgründen auch prozedurales Programmieren erlaubt. Programmiermethode

Anwendung

typische Problemklassen

prozedural

Numerik

Berechnungen

funktional

Lambda-Kalkül

Formelmanipulation

deklarativ

automatisches Beweisen

Prädikatenlogik 1.Stufe

objektorientiert

Klassifikation

Objekthierarchien

Tab. 1.1: Hierarchie der Programmiermethoden

Seit der NATO Software-Engineering Konferenz 1968 in Garmisch war die SoftwareKrise in aller Munde. David Gries schrieb darüber in The Science of Programming: Die Informatiker sprachen offen über das Versagen ihrer Software und nicht nur über ihre Erfolge, um auf den Grund der Probleme zu kommen. Zum ersten Mal kam es zur generellen Übereinkunft, dass es wirklich eine Software-Krise gab und dass das Programmieren noch nicht gut verstanden war. Man hatte erkannt, dass die herkömmlichen Programmiersprachen und -methoden nicht mehr ausreichten, um große Software-Projekte in den Griff zu bekommen. Folgende Qualitätsnormen wurden im Software-Engineering angestrebt: 왘 Korrektheit (Software soll exakt die Anforderungspezifikation erfüllen) 왘 Erweiterbarkeit (Maß für die Fähigkeit, Software an erweiterte Spezifikationen anzu-

passen) 왘 Wiederverwendbarkeit (Maß für die Möglichkeit, Software teilweise oder vollständig

für neue Anwendungen wiederzuwenden) 왘 Kompatibilität (Maß für die Fähigkeit, verschiedene Software-Produkte miteinander

zu kombinieren) Es entstanden eine Vielzahl von Entwicklungsumgebungen, die in der Regel objektorientiert konzipiert sind und nun als CASE-Tools (Computer Aided Software Engineering) auf dem Markt erscheinen. Welchen Umfang Software-Projekte haben können, sieht man am Quellcode von Windows 95, der ca. 750.000 Zeilen umfasst. Die Software zur Steuerung der Mondlandung von APOLLO 11 umfasste dagegen nur ca. 300.000 Programmzeilen. Was ist nun ein Objekt genau? Nach Shlaer/Mellor (1988) lassen sich alle Objekte in folgende fünf Kategorien einteilen: 왘 Erfassbare Dinge (z.B. Auto, Bankkonto) 왘 Rollen (z.B. Chauffeur, Kontoinhaber)

1.1 Was ist OOP?

17

왘 Ereignisse (z.B. Fahrt, Bankabrechnung) 왘 Interaktionen (z.B. Leasingvertrag, Auszahlung) 왘 Spezifikationen (z.B. kennzeichnende Eigenschaften).

Das OOP wird in der Literatur durch folgende Schlagworte gekennzeichnet: 왘 Geheimnisprinzip/ Datenkapselung (information hiding/ data encapsulation) 왘 Unterstützung abstrakter Datentypen (data abstraction) 왘 Vererbung (inheritance) 왘 Polymorphismus (polymorphism) 왘 Modularität (modularity) 왘 Wiederverwendbarkeit (reusability)

Abbildung 1.1: Prinzipien (Paradigma) der OOP

Dabei wurden die Konzepte Datenkapselung, Vererbung und Polymorphismus bereits 1965 von O.J. Dahl und K. Nygard für die Programmiersprache SIMULA erdacht, die später dann SIMULA 67 genannt wurde. Zu dieser Zeit war das Schlagwort Objektorientierung aber noch gar nicht geprägt! Unter Datenkapselung versteht man das Abschirmen eines Objekts und seiner Methoden nach außen. Die Kapselung ermöglicht es, Elemente und Funktionen einer Klasse gegen einen Zugriff von außen, z.B. von einem anderen Objekt, zu schützen. Bei der Vererbung können bestimmte Methoden des Objekts ausgeschlossen werden. Die Kapselung ist eine Anwendung des allgemeineren Geheimnisprinzips (information hiding), das 1972 von D. Parnas postuliert wurde: Jedes Programmmodul soll nach diesem Prinzip so wenig wie möglich über seine interne Arbeitsweise aussagen. Unter Vererbung versteht man die Fähigkeit eines Objekts, Eigenschaften und Methoden automatisch von einem anderen Objekt zu erben. Kann ein Objekt nur von einem anderen erben, so spricht man von einfacher Vererbung (single inheritance). Können jedoch Eigenschaften von mindestens zwei Objekten geerbt werden, so handelt es sich

18

1 Einleitung

um mehrfache Vererbung (multiple inheritance). Die vererbende Klasse heißt auch Basisklasse, die erbende Klasse abgeleitet. Unter Polymorphismus versteht man die Fähigkeit, dass verschiedene Objekte auf dieselbe Methode mit unterschiedlichen Aktionen reagieren können. In der Sprache von C++ heißt das, Objekte, die über einen Zeiger auf die Basisklasse angesprochen werden können, agieren so, als wären sie vom Typ der abgeleiteten Klasse (sofern sie vom Typ der abgeleiteten Klasse sind). Diese Zeiger können während eines Programmlaufs mehrere Werte annehmen. Der Compiler kann erst zur Laufzeit entscheiden, zu welchem Objekt die jeweils aufgerufene Methode gehört. Dieser Prozess heißt dynamisches Binden (dynamic binding) oder spätes Binden (late binding). Modularität bedeutet im Allgemeinen Wiederverwendbarkeit (reusability) und Erweiterbarkeit (extensibility). Wiederverwendbarkeit bedeutet, dass Programme aus bereits existierenden Software-Komponenten zusammengesetzt werden können. Mit Erweiterbarkeit ist gemeint, neue Software-Komponenten so zu schreiben, dass sie mit existierenden Programmen ohne Änderung kombiniert werden können. Nach B. Meyer umfasst die Modularität folgende Eigenschaften: 왘 Zerlegbarkeit (Systeme können in einzelne funktionierende Einheiten zerlegt wer-

den) 왘 Zusammenfügbarkeit (Einzelmodule können beliebig kombiniert werden) 왘 Verständlichkeit (Verstehen der Einzelmodule ermöglicht Verstehen des Ganzen) 왘 Kontinuität (kleine Änderungen des Systems bewirken nur eine kleine Änderung

im Verhalten der Software) 왘 Schutz (Ausnahmebehandlungen und Fehler wirken nur im verursachenden

Modul oder in seiner Nähe) Wiederverwendbarkeit ist aber in der Praxis nur schwer zu realisieren. E. Yourdon sagt darüber (1990): Wiederverwendbarkeit ist natürlich eine Pfadfindertugend, wie Treue, Tapferkeit und Mut; aber niemand weiß so richtig, wie man diese in die Tat umsetzen kann. Die prozedurale und objektorientierte Programmierung haben gewisse Ähnlichkeiten. Nach N. Wirth (1990) lassen sich folgende Analogien finden prozedural

objektorientiert

Datentyp

Klasse/Abstrakter Datentyp

Variable

Objekt/Instanz

Funktion/Prozedur

Methode

Funktionsaufruf

Senden einer Botschaft Tab. 1.2: Analogie prozedurales/objektorientiertes Programmieren

Alle Aspekte des prozeduralen Programmierens sind zu einem gewissen Grad auch im OOP vertreten. Anstatt weitgehend vom Datentyp unabhängige Funktionen und Prozeduren zu entwickeln, definiert man geeignete Methoden, die nun direkter Bestandteil der speziellen Objektklassen sind. Während man früher überlegt hat, durch welche Datenstrukturen ein Algorithmus optimal implementiert werden kann, werden Klassen bereits bei der Definition so konzipiert, dass sie der Struktur des Objekts und seines Datenaustausches entsprechen.

1.2 Warum C++?

19

Den Vorteilen des OOP stehen nur wenige Nachteile gegenüber, wie verstärkter Ressourcenbedarf, größere Planungskomplexität und komplizierte Entwurfstechniken. Neuere OOP-Programmierumgebungen mit grafischer Benutzeroberfläche (GUI, englisch Graphical User Interface) erfordern mehr Maschinenressourcen als textorientierte Editoren. Das erste GUI wurde im Xerox PARC (Palo Alto Research Center) entwickelt, von wo auch das SMALLTALK-Interface WIMP (Windows, Icons, Menus, Pointers) stammt. Als Vorstufen des OOP betrachtet man die objektorientierte Analyse (OOA) und das objektorientierte Design (OOD). Hier wurde eine Vielzahl von Entwurfstechniken entwickelt, die nun in der Unified Modelling Language (UML) zusammengefasst worden sind (mehr darüber in 9.3). Compiler und Codierung des OOP sind komplexer und anspruchsvoller geworden. Der Parser von C++ ist doppelt so groß wie der von ADA. C++ kann daher als die komplexeste Programmiersprache angesehen werden. Das Zusammenwirken von Objektklassen muss sorgfältig geplant werden, damit die Vererbung von Methoden und die Wiederverwendbarkeit von Klassen in gewünschter Weise genützt werden können. M. Terrible schreibt (1994): Objektorientierte Methoden versprechen mehr Erfolg für Programmierer und Software-Ingenieure. Lernen und Anwenden von C++ ist nicht dasselbe wie der Entwurf von objektorientierter Software. Ohne grundlegendes Wissen über Planung und Design von objektorientierten Systemen kann C++ nur begrenzten Erfolg haben. Das Programmieren in C++ steigert die Anstrengungen, die Systemspezialisten und Designer erbringen müssen, damit die Analyse stichhaltig, die Architektur überschaubar und das Design begründet ist und nicht zufällig geschieht.

1.2

Warum C++?

Die Grundlagen von C++ (damals noch unter dem Namen C mit Klassen) wurden 1979 bis 1984 von dem aus Dänemark stammenden Informatiker Bjarne Stroustrup bei den Bell Laboratories von AT&T gelegt. Damals, zu Beginn der achtziger Jahre, gab es eine Vielzahl von Bestrebungen, neue rein objektorientierte Sprachen – unabhängig von den bisherigen Programmiersprachen – zu entwickeln. Eine dieser Sprachen ist EIFFEL, das Mitte der achtziger Jahre von Bertrand Meyer konzipiert wurde. Eine Frühform von EIFFEL wurde in Object-Oriented Software Construction (1988) vorgestellt. Der endgültige Entwurf von EIFFEL wurde erst 1992 von Meyer publiziert in EIFFEL: The Language. Dieser Entwurf verfügt über mehr OOP-Konzepte als C++. Vom Standpunkt des reinen OOP gesehen, wäre eine ausschließlich objektorientierte Programmiersprache wie SMALLTALK oder EIFFEL vorzuziehen. Als Stroustrup sah, dass für SMALLTALK (Entwurf Alan Kay) nur ein Interpreter, für EIFFEL nur ein Entwurf existierte, wurde ihm klar, dass diese Sprachen nicht als Basis seines Projekts dienen konnten. Auch von der Vielzahl weiterer Programmiersprachen – darunter MODULA 2, ADA, MESA und CLU –, die Stroustrup in dieser Zeit studierte, konnte keine seinen Anforderungen genügen. So fügte er Teile von SIMULA 76, ALGOL 68 und C zu einem neuen Entwurf zusammen. Eine solche hybride Sprache war neben der Objektorientierung ebenfalls zum prozeduralen Programmieren geeignet.

20

1 Einleitung

Der Schwachpunkte der Programmiersprache C war sich Stroustrup sehr wohl bewusst, er erntete in diesem Zusammenhang viel Kritik, der Erfolg gab ihm aber Recht. Für C sprachen insbesondere folgende Punkte: 왘 Flexibilität 왘 Effizienz 왘 Verfügbarkeit 왘 Portabilität

C war sowohl zur Systemprogrammierung – wie UNIX zeigt – als auch zum technischnaturwissenschaftlichen Rechnen geeignet. Ferner unterstützte es – im Gegensatz etwa zu PASCAL – die Software-Entwicklung durch separates Compilieren. C erlaubte es, durch Bitoperationen teilweise auf Maschinenebene zu programmieren und sich damit jeder Rechnerarchitektur anzupassen. C war wie keine andere Sprache auf allen Betriebssystemebenen vertreten, insbesondere auf Mehrbenutzeranlagen wie UNIX. Außerdem galt C als portabel; durch die Einführung von Bibliotheksfunktionen konnten z.B. alle Ein- und Ausgaben maschinenunabhängig beschrieben werden. Stroustrup schreibt: A programming language serves two related purposes: it provides a vehicle for the programmer to specify the action to be executed and a set of concepts for the programmer to use when thinking about what can be done. Diese beiden Aspekte können auch charakterisiert werden als die Grundphilosophie von C: 왘 Nahe-an-der-Maschine 왘 Nahe-am-Problem

Der Schwachpunkt von C (vor der ANSI C-Norm), die fehlende Typenprüfung, sollte in C++ durch striktes Type-Checking überwunden werden. Da C++ weitgehend abwärtskompatibel ist, erfordert das saubere objektorientierte Programmieren in C++ erhöhte Programmierdisziplin. Für C++ spricht ferner die Möglichkeit, ein reines C-Programm mit einem C++-Compiler zu übersetzen. Davon wird von Programmierern häufig Gebrauch gemacht (nach dem Motto C++ as better C).

1.3

Die Entwicklung von C++

Bjarne Stroustrup kannte durch sein Studium in Cambridge die Programmiersprachen SIMULA 76 und ALGOL 68 gut. Nach seinem Eintritt in die Bell Laboratories in London hatte er sich intensiv mit C zur Systemprogrammierung befasst. Als er im Frühjahr 1979 zu AT&T (New Jersey) wechselte, wurde er mit der Aufgabe betraut, den Kern von UNIX so zu modifizieren, dass das System auch in einem lokalen Netzwerk lief. Als Folge seiner Arbeit erschien 1980 die erste Publikation über C mit Klassen in einem internen Bericht von Bell Labs. Dieser Report sah folgende Eigenschaften vor: 왘 Klassen (mit privatem/öffentlichem Zugriff) 왘 Einfache Vererbung (aber noch keine virtuelle Funktionen)

1.3 Die Entwicklung von C++

21

왘 Konstruktoren/Destruktoren 왘 Friend-Klassen 왘 Konstanten 왘 Überladen von Operatoren 왘 Referenzen

Das Klassenkonzept übernahm Stroustrup aus SIMULA 76, das Operator-Überladen entlehnte er aus ALGOL 68. Der 1982 erschienene SIGPLAN-Report Adding Classes to the C Language: An Exercise in Language Evolution umfasste zusätzlich noch 왘 Inline-Funktionen 왘 Default-Argumente 왘 Überladen des Zuweisungsoperators

1984 erkannte Stroustrup, dass der Erfolg seiner Bemühungen nur eine eigenständige Sprachentwicklung sein konnte und nicht eine Ergänzung einer existierenden Sprache. Diese Entwicklung wurde zunächst C84, später dann, auf Vorschlag seines Kollegen R. Mascitti, C++ genannt. Zur weiteren Verbreitung musste natürlich ein geeigneter (Prä-)Compiler bereitgestellt werden. Die Version 1.0 von Cfront erschien 1985 und umfasste ungefähr 12.000 Programmzeilen C++. Die weiteren Cfront-Versionen bis 3.0 erschienen bis September 1991. Die Version 1.0 war in der 1986 erschienenen Sprachendefinition The C++ Programming Language zugrunde gelegt. Mit der Version 2.0 wurde C++ u.a. um folgende Funktionen erweitert 왘 Mehrfache Vererbung 왘 Abstrakte Klassen 왘 Statische und konstante Elementfunktionen

Die Version 2.1 wurde durch das Referenzwerk: The Annotated C++ Reference Manual (ARM genannt) im April 1990 festgelegt. Hierbei wurde noch folgenden Eigenschaften hinzugefügt 왘 Templates 왘 Virtuelle Funktionen 왘 Ausnahmen (Exceptions) 왘 Verbesserte Ein-/Ausgabe (mittels iostream)

Eine modifizierte Version des Cfront 3.0-Compilers, die im September 1992 von Hewlett-Packard verschickt wurde, unterstützte diese Neuerungen, einschließlich den Ausnahme-Behandlungen (exceptions handling). Diese Version ist praktisch von allen Compilerherstellern übernommen worden, u.a. von Apple, Centerline, Glockenspiel, PARC Place und SUN. Das im Dezember 1989 ins Leben gerufene ANSI C++-Komitee sorgte für eine gute Abstimmung mit der gleichzeitig entstehenden ANSI C-Norm. Für die Zusammenarbeit galt die Devise As Close to C as possible – but not closer. Die Liste der 1990 im ANSI C++-Komitee vertretenen Firmen liest sich wie das Who is Who der Computerindustrie:

22

1 Einleitung

Amdahl, Apple, AT&T, Borland, British Aerospace, CDC, DEC, Fujitsu, Hewlett-Packard, IBM, Los Alamos National Labs, Lucid, Microsoft, NEC, Prime Computer, SAS, Siemens, Silicon Graphics, Sun, Texas Instruments, UniSys, Wang, Zortech u.a. Bereits im Mai 1990 hatte Borland einen C++-Compiler in die MS-DOS-Welt gebracht, von dem bis zur COMDEX 1993 mehr als eine Million Exemplare verkauft wurden (Zortech hatte seit 1988 einen C++-Compiler für MS-DOS angeboten). Microsoft zog erst im März 1992 durch die Übernahme des Glockenspiel-Compilers nach. Auf der UNIX-Seite sind die Compiler der USENIX-Gruppe, GNU C++ (seit Dezember 1987) zu nennen. Für X-Windows Systeme gibt es die komfortablen Versionen von SUN und Centerline. 1993 wurden folgende Erweiterungen vom ANSI/ISO C++-Komitee beschlossen: 왘 Run-Time Type Identification (RTTI) 왘 Namensraum (namespace)

Ein wesentlicher Schritt war auch die Akzeptanz der von Alexander Stepanow und Meng Lee bei Hewlett Packard entwickelten Standard Template Library (STL), die 1994 weitgehend, aber nicht ganz, vom ANSI/ISO-Komitee verfügt wurde. In die kommende Norm wurden schließlich noch neue Operatoren zur Typumwandlung aufgenommen wie 왘 static_cast, dynamic_cast 왘 const_cast, reinterpret_cast

Am 26. September 1995 wurde dann endlich der lang erwartete Normenentwurf Draft ANSI/ISO C++ Standard beschlossen. Nach langen Verhandlungen dauerte es dann noch fast drei Jahre, bis am 27. Juli 1998 die ANSI C++-Norm, international als ISONorm 14882:1998, endgültig beschlossen war. Die Publikation umfasst 774 Seiten und ist elektronisch als *.pdf-File verfügbar. Momentan sammelt das ISO-Komitee über die nationalen Komitees und User-Gruppen Fehler-Reports (defect reports), die über Unklarheiten, Widersprüche oder Auslassungen der Norm Auskunft geben. In etwa zwei Jahren werden dann alle, vom Komitee akzeptierten Reports, als Technical Corrigendum (TC) publiziert. Die Publikation zweier solcher TC ist möglich; erst nach 2003 kann es zu einer letzten Bewertung (final review) der ISO-Norm kommen. Damit war nach fast zehnjähriger Arbeit die umfangreichste internationale Normierung zu einem Schlusspunkt gekommen. Alle Programmierer und Software-Firmen haben nun die Sicherheit, dass ein der Norm entsprechendes C++-Programm nie mehr geändert werden muss! Für viele Informatiker ist der Umfang von C++ bereits zu groß. Stroustrup war stets darauf bedacht, den Umfang von C++ in Grenzen zu halten. Er wollte damit vermeiden, dass C++ nur noch von einer Handvoll Spezialisten verstanden wird und damit das Schicksal von ALGOL 68 teilt. Wie das OOP-Konzept in C++ realisiert wurde, zeigt die Tabelle im Überblick.

1.4 Die Weiterentwicklung von C

OOP-Konzept

Realisation in C++

Klasse

class

Instanz

Variable oder Objekt vom Typ class

Instanzvariable

class-Komponente

23

Klassenvariable

statiche class-Komponente

Methode

class-Komponentenfunktion

Klassenmethode

statische class-Komponentenfunktion

Protokoll

Deklaration aller Methoden

Vererbung

einfache/mehrfache Vererbung

Abstrakte Klasse

Klasse mit rein virtuellen Methoden

Parametrisierte Typen

Templates

Polymorphismus

Überladen von Funktionen/Operatoren, virtuelle Funktionen

Dynamisches Binden

virtuelle Funktionen Tab. 1.3: Realisierung der OOP-Konzepte in C++

1.4

Die Weiterentwicklung von C

Die ANSI/ISO C-Norm war Ende 1989 verabschiedet worden und wurde als ISO/IEC 9899:1900 publiziert. Damit war die Arbeit der ANSI C++-Gruppe keineswegs beendet. Die Bemühungen um eine Internationalisierung führten 1995 zu einer Ergänzung der C-Norm, dem Amendment 1, das zum ersten Mal auch internationale Zeichensätze in C einführte. Dazu erschien eine eigene Norm ISO/IEC 10646, die den Universal Multiple Octet Coded Character Set (UCS) definiert. Auf diese Norm geht die HeaderDatei zurück, die dann auch in C++ übernommen wurde. Java war also keineswegs die erste Programmiersprache, die internationale Zeichensätze unterstützte. Auch ein weiteres internationales Komitee NCEG (Numerical C Extensions Group) beschäftigte sich mit der Weiterentwicklung von C; insbesondere strebte man eine Standardisierung des Parallelrechnens und der Fließpunkt-Arithmetik an. Für das numerische Rechnen wurde ein eigener doppelt-genauer komplexer Zahlentyp long double complex entwickelt. Auch die Diskussionen und Arbeitspapiere des ANSI C++-Komitees wurden von der C-Gruppe zur Kenntnis genommen. Über ein Jahr diskutierte eine Untergruppe, ob und wie man objektorientierte Eigenschaften von C++, wie einfache Vererbung, Zugriffskontrolle und virtuelle Funktionen, in C zulassen sollte. Aus verschiedenen Gründen wurde dies aber später verworfen. Viele (nicht objektorientierte) Sprachelemente von C++ wurden aber als nützlich erkannt, unter anderem die Form der Kommentierung (mittels //), der bool-Typ (Schlüsselwort _BOOL), der sizeof-Operator und anderes mehr. Alle diese Bemühungen mündeten in der Verabschiedung einer neuen Norm ANSI/ ISO 9899:1999 für die nunmehr C99 genannte Programmiersprache. Wichtige Neuerungen von C99 sind:

24

1 Einleitung

왘 Neue Datentypen wie long long, long double complex und long double imaginary. 왘 Erweiterte int-Typen wie int32_t. 왘 Erweiterte Möglichkeiten bei der Fließpunkt-Arithmetik (Rundungsregeln, Aus-

nahmefälle). 왘 Übernahme von C++-Elementen wie const, sizeof und der Blockstruktur der Kon-

trollstrukturen; Letzteres erlaubt nun Definitionen innerhalb der FOR-Schleife. 왘 Arrays mit variabler Länge. 왘 Verkürzte Initialisierung von Strukturen.

1.5

Java als C++-Derivat Java is a new object-oriented programming language developed at Sun Microsystems to solve a number of problems in modern programming practice and to provide a programming language for the Internet. Java Homepage der Fa. SUN

1990 hatte der Software-Ingenieur J. Gosling begonnen, im Auftrag der Fa. SUN unter dem Projektnamen OAK eine neue objektorientierte Sprache zu entwickeln. Die Vorgaben waren 왘 einfache Entwicklungsmöglichkeiten von Applikationen 왘 Stabilität und Zuverlässigkeit von Programmen 왘 Plattformunabhängigkeit

Als Syntaxbasis wurde ein abgespecktes C++ verwendet. Das OAK-Projekt wurde 1994 auf Eis gelegt, da die Medienkonzerne wie Time Warner kein Interesse zeigten. Aus urheberrechtlichen Gründen wurde OAK in Java umbenannt. Als jedoch im Herbst gleichen Jahres P. Naughton und J. Payne einen WWW (World Wide Web)-Browser für SUN entwickelten, konnten sie auf die Grundlagen von OAK zurückgreifen. Im Januar erhielt dieser Browser den Namen HotJava. Die Möglichkeiten, die der Browser bot, waren bahnbrechend, sodass SUN das Java-Projekt als ClientServer-Technologie wieder aufnahm. Um Java populär zu machen, stellte SUN die Programmiersprache im Mai 1995 ins Internet. Dort gewann diese Sprache bei Internet-Surfern und Computerzeitschriften eine ungeheure Popularität, erlaubt Java doch neben separaten Programmen (Applikationen) auch die Ausführung eines so genannten Applets innerhalb einer WWW-Seite. Dieses Applet kann sogar an irgendeiner Internet-Adresse (URL, englisch Uniform Resource Locator) vorliegen. Hinzu kommt, dass nicht einmal ein Compiler notwendig ist; die Interpretation übernimmt ein passender Internet-Browser. Die damit eröffneten Möglichkeiten der Interaktivität und Animation gehen weit über das hinaus, was die Seitenbeschreibungssprache HTML (HyperText Markup Language) vermag. HTML ist ein Derivat der von IBM entwickelten General Markup Language (GML), die später als SGML (Standard General Markup Language) zur ISO-Norm erhoben wurde.

1.5 Java als C++-Derivat

25

Java erhielt von C++ die Syntax, die Kontrollstrukturen (bis auf goto) und die einfachen Datentypen (bis auf char, enum, struct, union). Für den Zeichensatz wurde der 16Bit-Uni(-versal)code gewählt, der aus HTML bekannt ist. Damit wurde das leidige Problem der westeuropäischen Umlaute und der asiatischen Sprachen gelöst. Alle einfachen Datentypen wurden einheitlich als vorzeichenbehaftet (signed) festgelegt, die Bytezahl von int-Typen wurde auf vier fixiert. Ebenfalls übernommen wurden die einfache Vererbung und die Ausnahmefälle (exceptions). C-Funktionen wie malloc(), die einen direkten Speicherzugriff gestatten, wurden aus Sicherheitsgründen außer Kraft gesetzt. Nicht mehr enthalten sind die mehrfache Vererbung, die Template-Klassen und die Möglichkeit, nicht objektorientiert zu programmieren. Das folgende Beispiel eines Applet zeigt die formale Ähnlichkeit mit C++: import java.awt.*; import java.applet.*; public class KurveApp extends Applet // einfache Vererbung von Applet auf KurveApp { int f(double x) // Schwebungsfunktion {return (int)((Math.cos(x/5)+Math.sin(x/7)+2)*50); } public void paint(Graphics g) { for (int x=0; x " 51 32 13 27 8 46 -> 46 27 13 8 32 -> 32 13 8 27 -> 27 8 13 -> 13 8 -> 8

Den aufgebauten Heap mit Standardnummerierung zeigt Abbildung 16.1.

16.10 Komplexe Arithmetik Die Klasse complex gehört ebenfalls zur Standardbibliothek von C++. Sie ist zwar als Template definiert: templateclass complex {};

besitzt aber für die wichtigsten Einsetzungen separate Klassen, sodass bessere Eingabemöglichkeiten verfügbar und keine Umwandlungen mehr notwendig sind, speziell für:

16.10 Komplexe Arithmetik

367

Abbildung 16.1: Heap des Programmbeispiels

complex complex complex

Folgende wichtige Elementfunktionen sind definiert: real() // Realteil imag() // Imaginärteil norm() // Betragsquadrat abs() // Betrag arg() // Argument polar() // Polarform

und alle komplexen Standardfunktionen wie sin(), sinh(), cos(), cosh(), exp(), log(), log10(), sqrt(), tan() und tanh(). Ferner sind alle arithmetischen Operatoren (einschließlich Vorzeichen) überladen; an Vergleichsoperatoren existieren nur == und !=, da bekanntlich die Menge der komplexen Zahlen keine Ordnungsrelation besitzt. Der Ausgabe-Operator > akzeptiert komplexe Zahlen in der Form r, (r) und (r,i). Als erstes Beispiel wird eine quadratische Gleichung mit reellen Koeffizienten gelöst. Dabei wird ein Ausnahmefall geworfen, wenn keine quadratische Gleichung vorliegt. // quadglch.cpp #include #include #include #include #include using namespace std; typedef complex komplex;

368

16 Algorithmen der STL

void quadglch(double a,double b,double c,komplex& x1,komplex& x2) { double diskr; x1 = komplex(0,0); x2 = komplex(0,0); try{ diskr = b*b-4.*a*c; if (fabs(a)= 0) { double d = sqrt(diskr); x1 = komplex((-b+d)/(2*a),0); x2 = komplex((-b-d)/(2*a),0); } else{ double d = sqrt(fabs(diskr)); x1 = komplex(-b/(2*a),d/(2*a)); x2 = komplex(-b/(2*a),-d/(2*a)); } } catch(char* error) { cerr > b >> c; quadglch(a,b,c,x1,x2); cout