131 89 4MB
German Pages 485 Year 2000
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
Klassenvariable
statiche class-Komponente
Methode
class-Komponentenfunktion
Klassenmethode
statische class-Komponentenfunktion
Protokoll
Deklaration aller Methoden
Vererbung
einfache/mehrfache Vererbung
23
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