C++ steht in dem Ruf, eine besonders mächtige und leistungsfähige, aber leider auch eine sehr schwer zu erlernende Programmiersprache zu sein. Letzteres ist wohl darauf zurückzuführen, dass die vielfältigen Möglichkeiten und die Freiheiten, die C++ dem Programmierer bietet, einer ebenso großen Zahl an Konzepten, Techniken und unterschiedlichen Syntaxformen gegenüberstehen. Und gerade diese Syntaxformen – das lässt sich nicht leugnen – können auf Anfänger schon recht abschreckend wirken. Einige Kostproben gefällig? Zeilen der Form:
virtual const char* f() const noexcept;
sind in C++ keineswegs unüblich und auch Berechnungen der Form:
i = m++*+n;
sind möglich. Besondere Freude bereiten aber Deklarationen wie z. B.:
int *(*f(int))(int, int);
Falls Ihnen jetzt Zweifel kommen, ob Sie mit C++ wirklich die richtige Wahl getroffen haben, so lassen Sie sich versichern:
C++ ist viel einfacher, als es manchmal den Anschein hat.
Schon bald werden Sie Ihre eigenen C++-Programme schreiben.
Mit jedem Programm, das Sie schreiben, wird Ihnen C++ vertrauter und selbstverständlicher erscheinen.
Am Ende dieses Buchs werden Sie nicht nur in der Lage sein, attraktive und professionelle Programmvorhaben anzugehen, Sie werden auch verstehen, was die erste der obigen Beispielzeilen bedeutet, und Sie werden den Kopf darüber schütteln, warum der Verfasser der eigentlich doch ganz einfachen zweiten Beispielzeile den Code nicht lesefreundlicher formatiert hat.
Nur die Bedeutung der dritten Beispielzeile werden Sie nach der Lektüre dieses Buchs immer noch nicht verstehen. Aber trösten Sie sich: Die Konstruktion, die in dieser Zeile deklariert wird 1, ist so abgehoben, dass Sie unter zehn professionellen C++-Programmierern vermutlich höchstens einen finden werden, der diese Konstruktion erkennt, geschweige denn sie selbst schon einmal eingesetzt hätte.
Warum aber ist C++ so mächtig? Warum gibt es so viele Konzepte in der Sprache und warum ist die Syntax so kryptisch? Die Antwort auf diese Fragen liegt in der Geschichte von C++.
"The times they are a changin´" – die Zeiten ändern sich – heißt es in einem berühmten Song von Bob Dylan. Sicherlich hatte Dylan dabei nicht die Entwicklungen in der IT-Branche und der Softwareerstellung im Auge, doch allgemeine Wahrheiten lassen sich eben auf viele verschiedene Bereiche anwenden – und manchmal eben auch auf den Bereich der Softwareentwicklung.
Dort hat im Laufe der letzten Jahrzehnte tatsächlich ein grundlegender Wandel stattgefunden.
Wann die Entwicklung des Computers, der Rechenmaschine, begonnen hat, ist gar nicht so leicht zu sagen. Es hängt sehr davon ab, wie weit man zurückgehen möchte. In einer Aprilausgabe der renommierten Fachzeitschrift "Spektrum der Wissenschaften" wurde vor einigen Jahren beispielsweise von einer Aufsehen erregenden Entdeckung berichtet: Amerikanische Archäologen hatten auf einer Insel bei Neuguinea einen frühzeitlichen Computer entdeckt. Aus Seilen und Rollen hatten die Ureinwohner aus der Elektronik bekannte Schaltbausteine wie AND-Gatter, OR-Gatter und Inverter erstellt und zu einem echten Rechenwerk zusammengesetzt. Die Archäologen nahmen an, dass die damalige Priesterkaste diesen "Computer" als eine Art Orakel betrieb und ihr Wissen um die Konstruktion dieses Orakels zum Machterhalt nutzte. Schematische Abbildungen zur Funktionsweise des Rechenwerks und eine Einführung in die digitale Schaltungslogik rundeten den Artikel ab. Natürlich handelte es sich um einen Aprilscherz, aber immerhin: Unter dem Eindruck von so viel Logik und Wissenschaft blieb der gesunde Menschenverstand einiger Leser auf der Strecke. In den nachfolgenden Monaten ergingen daraufhin einige böse Briefe an die Redaktion von aufgebrachten Lesern, die die sensationelle Nachricht sofort weiterverbreitet und sich dabei bei ihren Professoren und Kollegen blamiert hatten.
Nicht ganz so weit zurückliegend, dafür aber verbrieft, ist die Erfindung des Lochkartensystems durch den Deutsch-Amerikaner Hermann Hollerith. Um das Jahr 1890 entwickelte er ein Verfahren, bei dem Daten durch Lochung bestimmter Felder auf vorgefertigten Karten (eben den Lochkarten) kodiert und festgehalten wurden. Mit Hilfe spezieller Maschinen, den sogenannten Hollerith- oder Lochkartenmaschinen, konnte man diese Daten automatisch auswerten, beispielsweise zur Erstellung von Serienbriefen, zur statistischen Datenerfassung oder allgemein zur Auswertung großer Datenmengen.
Der erste offiziell anerkannte, noch mechanische Computer war der 1936 gebaute Z1 des Berliners Konrad Zuse. Kurz darauf folgten Röhren-, später Transistoren- und schließlich Chip-Rechner. In der Zwischenzeit hatte sich auch bei der Softwareentwicklung Einiges getan: Anstatt Lochkarten zu stanzen, gab man Maschinenbefehlprogramme über ein Terminal ein. Irgendwann wurden die Maschinenbefehle durch die Sprache Assembler ersetzt und schließlich kamen die ersten höheren Programmiersprachen, die interpretiert oder kompiliert wurden.
Interpreter und Compiler
Maschinenbefehle sind "Wörter", die aus einer Folge von Nullen und Einsen bestehen, also beispielsweise 0011000010101011. Das eigentliche Rechenwerk eines Computers, der Prozessor, versteht nur diese binären Befehle (wobei noch zu beachten ist, dass jeder Prozessortyp seinen eigenen spezifischen Sprachschatz hat). Da das Programmieren mit diesen Befehlen für Menschen viel zu mühsam und schwierig ist, kam man auf die Idee, die Programmquelltexte in einer anderen Sprache aufzusetzen und dann mit Hilfe eines passenden Übersetzerprogramms in Maschinenbefehle umschreiben zu lassen. Die üblichen menschlichen Sprachen sind aber viel zu komplex und uneindeutig, um sie maschinell übersetzen zu können. Aus diesem Grunde wurden eigene Programmiersprachen wie C oder Basic entwickelt, mit einfacher Grammatik und geringem Wortschatz, die für Menschen leichter zu erlernen und für Übersetzerprogramme leichter in Maschinenbefehle umzusetzen sind.
Grundsätzlich gibt es zwei Kategorien von Übersetzerprogrammen: die Interpreter und die Compiler.
Ein Interpreter lädt den Quelltext des Programms, übersetzt ihn stückweise und lässt die übersetzten Anweisungen direkt vom Prozessor ausführen. Endet das Programm, endet auch die Ausführung des Interpreters.
Ein Compiler lädt den Quelltext des Programms, übersetzt ihn komplett (wobei er auch kleinere Optimierungen vornehmen kann) und speichert das kompilierte Programm in einer neuen Datei (unter Windows eine .exe-Datei) auf der Festplatte. Wenn der Anwender die .exe-Datei danach aufruft, wird das Programm direkt vom Betriebssystem geladen und ausgeführt.
Bild 1.1 Schematische Darstellung der Arbeit eines Interpreters und eines Compilers. (Beachten Sie, dass bei der Kompilierung das fertige Programm nur auf Rechnern ausgeführt werden kann, deren Architektur und Betriebssystemfamilie zu dem Rechner des Programmierers kompatibel sind.)
Ein interpretiertes Programm kann auf jedem Rechner ausgeführt werden, auf dem ein passender Interpreter verfügbar ist. Die Ausführung ist allerdings langsamer und der Quelltext des Programms ist für jeden einsehbar. 2
Ein kompiliertes Programm kann nur auf Rechnern ausgeführt werden, deren Plattform (Prozessor/Betriebssystem-Kombination) die Maschinenbefehle versteht, die der Compiler erzeugt hat. Dafür kann der Code für die Plattform optimiert werden, ist aufgrund der Binärkodierung vor geistigem Diebstahl weitgehend geschützt und wird schneller ausgeführt, da kein Interpreter zwischengeschaltet werden muss.
1.1.2 | Die strukturierte Programmierung |
Anfangs erlaubten die Programmiersprachen nur Programme, in denen die einzelnen Anweisungen, die der Computer bei Ausführung des Programms abarbeiten sollte, von oben nach unten im Programmquelltext angegeben werden mussten.
1. Tue dies
2. Tue das
3. Mache jetzt jenes
4. ...
Programmieranfänger dürfte dieses Prinzip begeistern, denn es ist leicht zu verstehen. Doch in der Praxis stellte sich damals bald heraus, dass diese Art der Programmierung ihre Grenzen hat: Einmal implementierte Teillösungen lassen sich schlecht wiederverwerten, größere Programme sind mangels Strukturierung...