Willkommen zu C++ in 21 Tagen! Heute werden Sie die ersten Schritte machen, mit dem Ziel, ein erfolgreicher C++-Programmierer zu werden. Sie lernen,
Programmiersprachen haben seit den ersten elektronischen Computern, die zur Berechnung
der Flugbahnen von Kanonenkugeln im 2. Weltkrieg gebaut wurden, eine
dramatische Wandlung erfahren. In der Gründerzeit arbeiteten die Programmierer mit
den primitivsten Computer-Anweisungen: Maschinensprache. Diese Anweisungen
stellte man durch lange Folgen von Einsen und Nullen dar. Mit Einführung der Assembler
ließen sich die Maschinenanweisungen durch besser verständliche Mnemonics wie
ADD
und MOV
abbilden.
Im Laufe der Zeit entstanden höhere Programmiersprachen wie BASIC und COBOL.
Diese Sprachen erlauben die Arbeit in einer der natürlichen Sprachen (in der Regel
Englisch) ähnlichen Sprache wie Let I = 100
. Diese Anweisungen übersetzen Interpreter
und Compiler in die Maschinensprache. Ein Interpreter liest den Quellcode eines
Programms, übersetzt dabei die Anweisungen - oder den Code - und wandelt sie
direkt in Aktionen um. Ein Compiler überführt den Code in eine Art Zwischenform -
diesen Schritt nennt man Kompilieren - und erzeugt damit eine Objektdatei. Der
Compiler ruft anschließend einen Linker auf, der die Objektdatei in ein ausführbares
Programm umwandelt.
Da Interpreter den Code genauso lesen, wie er niedergeschrieben wurde, und den Code unmittelbar ausführen, stellen sie ein leicht anzuwendendes Arbeitsmittel für den Programmierer dar. Bei Compilern sind zusätzliche Schritte zum Kompilieren und Linken des Codes erforderlich, was etwas umständlicher ist. Andererseits produzieren Compiler ein Programm, das wesentlich schneller in der Ausführung ist, da die zeitraubende Aufgabe, den Quellcode in die Maschinensprache umzuwandeln, bereits erledigt wurde.
Ein weiterer Vorteil vieler kompilierter Sprachen wie C++ ist, daß das ausführbare Programm auch an Leute weitergegeben werden kann, die nicht über den Compiler verfügen. Bei einem Programm, das mit Interpreter-Sprache erstellt wurde, müssen Sie zur Ausführung des Programms auch den Interpreter haben.
Einige Sprachen, zum Beispiel Visual Basic, nennen den Interpreter die Laufzeit-Bibliothek. Bei Java heißt der Laufzeit-Interpreter Virtuelle Maschine (VM) und wird im übrigen von den Browsern (das heißt Internet Explorer oder Netscape) zur Verfügung gestellt.
Über viele Jahre hinweg bestand das hauptsächliche Ziel der Programmierer darin, kurze und schnelle Codestücke zu schreiben. Das Programm mußte klein sein, da Hauptspeicher teuer war, und es mußte schnell sein, da Rechenzeit ebenfalls einen nicht unerheblichen Kostenfaktor darstellte. Computer wurden kleiner, billiger und schneller, die Speicherpreise sind gefallen, und somit haben sich die Prioritäten geändert. Heutzutage überwiegen die Kosten für einen Programmierer bei weitem die Kosten der meisten geschäftlich genutzten Computer. Gut geschriebener und leicht zu wartender Code steht nun an erster Stelle. Leicht zu warten bedeutet dabei, daß sich das Programm bei sich ändernden Anforderungen ohne großen Kostenaufwand erweitern und verbessern läßt.
Das Wort Programm wird in zweierlei Hinsicht benutzt: zur Beschreibung einzelner Anweisungen (oder Quellcodezeilen) eines Programmierers oder zur Beschreibung einer kompletten, ausführbaren Software. Diese Unterscheidung kann einige Verwirrung hervorrufen. Deshalb werde ich hier in dem einen Fall von Quellcode und im anderen Fall von ausführbarem Programm sprechen.
Ein Programm kann entweder definiert werden als ein Satz geschriebener Anweisungen eines Programmierers oder als eine ausführbare Software-Datei.
Es gibt zwei Möglichkeiten, Quellcode in ein ausführbares Programm zu überführen: Interpreter übersetzen den Quellcode in Computerbefehle, und der Computer führt diese Befehle sofort aus. Alternativ kann der Quellcode von Compilern in ein Programm überführt werden, das zu einem späteren Zeitpunkt gestartet werden kann. Zwar sind Interpreter in der Anwendung einfacher, doch ernsthaft programmiert wird vornehmlich mit Compilern, da kompilierter Code wesentlich schneller ausgeführt werden kann. C++ ist so eine kompilierte Programmiersprache.
Die Probleme, mit denen Programmierer im Laufe der Jahre konfrontiert wurden, haben sich erheblich geändert. Vor zwanzig Jahren wurden Programme erzeugt, um große Mengen an Rohdaten zu verarbeiten. Die Erzeuger des Codes und die Nutzer des Programms waren ausnahmslos Computerexperten. Heutzutage werden Computer von wesentlich mehr Menschen genutzt, die zum größten Teil über nur begrenzte Computer- und Programmierkenntnisse verfügen. Computer sind lediglich Werkzeuge, die von Menschen genutzt werden, die eher daran interessiert sind, ihre Firmenprobleme zu lösen als sich mit dem Computer abzumühen.
Ironischerweise sind die Programme im gleichen Zuge komplexer geworden, wie es dem neuen Anwenderkreis einfacher gemacht wurde. Die Tage sind vorbei, als Benutzer kryptische Befehle hinter esoterischen Prompts eingaben, nur um einen Strom Rohdaten zu sehen. Heute verfügen Programme über anspruchsvolle, benutzerfreundliche Schnittstellen mit einer Unzahl von Fenstern, Menüs, Dialogfeldern und einer Myriade von Symbolen, mit denen wir alle inzwischen nur zu vertraut sind. Die Programme, die diesen neuen Ansatz unterstützen, sind wesentlich komplexer als jene, die vor zehn Jahren geschrieben wurden.
Mit der Entwicklung des Webs haben Computer einen neue Ära der Marktdurchdringung eingeläutet. Mehr Menschen als je zuvor benutzen Computer und ihre Erwartungen sind sehr hoch. In den wenigen Jahren seit der ersten Auflage dieses Buches sind die Programme umfangreicher und komplexer geworden, und der Bedarf an Techniken der objektorientierten Programmierung, um dieser Komplexität Herr zu werden, zeigt sich jetzt deutlich.
Im gleichen Maße wie sich die Anforderungen an die Programme geändert haben, haben sich auch die Programmiersprachen und die Techniken zum Schreiben von Programmen weiterentwickelt. Auch wenn der ganze Werdegang interessant ist, konzentriert sich dieses Buch auf den Übergang von der prozeduralen zur objektorientierten Programmierung.
Bis vor kurzem stellte man sich Programme als eine Folge von Prozeduren vor, die auf einen Satz von Daten ausgeführt wurden. Eine Prozedur, oder auch Funktion, ist ein Satz spezifischer Anweisungen, die nacheinander ausgeführt werden. Die Daten wurden getrennt von den Prozeduren gehalten und der Trick bei der Programmierung lag darin, sich zu merken, welche Funktion welche anderen Funktionen aufrief und welche Daten geändert wurden.
Um etwas Vernünftiges aus dieser eventuell verwirrenden Situation zu machen, wurde die strukturierte Programmierung erzeugt.
Der Grundgedanke der strukturierten Programmierung läßt sich auf die Formel »teile und herrsche« bringen. Ein Computerprogramm kann man sich auch als einen Satz von Aufgaben vorstellen. Jede Aufgabe, deren Beschreibung zu komplex ist, wird in eine Menge kleinerer Teilaufgaben zerlegt. Das setzt man solange fort, bis die Teilaufgaben klein genug sind, um bequem gelöst zu werden, dabei aber noch groß genug sind, um in sich abgeschlossenen zu sein und einen vernünftigen Zweck zu erfüllen.
Zum Beispiel ist die Berechnung des Durchschnittsgehalts aller Beschäftigten einer Firma eine ziemlich komplexe Aufgabe. Man kann diese allerdings in die folgenden Teilaufgaben zerlegen:
Punkt 3 läßt sich weiter in folgende Teilaufgaben gliedern:
Das Abfragen eines Beschäftigtendatensatzes kann wiederum in folgende Aufgaben unterteilt werden:
Die strukturierte Programmierung ist nach wie vor ein enorm erfolgreicher Lösungsansatz bei komplexen Aufgabenstellungen. Ende der Achtziger zeichneten sich jedoch die Schwächen der strukturierten Programmierung deutlich ab.
Zum einen ist es nur natürlich, sich die Daten (Datensätze der Beschäftigten zum Beispiel) und die Aktionen mit diesen Daten (sortieren, bearbeiten usw.) als eine Einheit vorzustellen. Die prozedurale Programmierung steht diesem entgegen, da sie die Datenstrukturen von den Funktionen, die die Daten manipulieren, trennt.
Zweitens stellten Programmierer fest, daß sie das Rad immer wieder neu erfanden, das heißt sie fanden regelmäßig neue Lösungen für alte Probleme - das Gegenteil der Wiederverwendbarkeit. Der Gedanke hinter der Wiederverwendbarkeit ist der Aufbau von Komponenten mit bekannten Eigenschaften. Diese Komponenten fügt man dann bei Bedarf in ein Programm ein. Dieses Modell entspricht der Hardware-Welt - wenn ein Techniker einen neuen Transistor benötigt, erfindet er ihn in der Regel nicht neu, sondern sucht sich aus seinen Beständen den passenden heraus und modifiziert ihn vielleicht. Für den Software-Techniker gab es keine vergleichbare Möglichkeit.
Die Art und Weise, wie wir jetzt Computer benutzen - mit Menüs und Schaltflächen und Fenstern - begünstigt einen interaktiveren, ereignisorientierten Ansatz der Computerprogrammierung. Ereignisorientiert bedeutet, daß ein Ereignis eintritt - der Benutzer drückt einen Schalter oder trifft eine Auswahl aus einem Menü - und das Programm muß reagieren. Programme werden zunehmend interaktiver und im gleichen Maße ist es wichtig, den Entwurf auf diese Art der Funktionalität auszurichten.
Veraltete Programme zwangen den Benutzer schrittweise, das heißt Bildschirm für Bildschirm, Dialog für Dialog, sich durch das Programm zu mühen. Moderne, ereignisorientierte Programme stellen alle Optionen direkt zur Verfügung und antworten auf Benutzeraktionen.
In der objektorientierten Programmierung wird versucht, auf diese Bedürfnisse einzugehen und Techniken bereitzustellen, die dieser enormen Komplexität Herr werden, die Wiederverwendbarkeit der Software-Komponenten ermöglichen und die Daten mit den Aufgaben zur Datenmanipulation verbinden.
Das Wesen der objektorientierten Programmierung besteht in der Behandlung der Daten und der Prozeduren, die auf diesen Daten arbeiten, als geschlossenes »Objekt« - eine selbständige Einheit mit einer Identität und eigenen Charakteristika.
C++ unterstützt voll die objektorientierte Programmierung (OOP), einschließlich der drei Säulen der objektorientierten Entwicklung: Kapselung, Vererbung und Polymorphie.
Wenn der Elektroniker einen Widerstand für ein Gerät benötigt, das er entwickeln möchte, baut er in der Regel keinen neuen, sondern sucht sich anhand der Farbetiketten, die die Eigenschaften anzeigen, den geeigneten Widerstand aus seinen Beständen heraus. Für den Elektroniker ist der Widerstand eine »Black Box« - er kümmert sich nicht speziell darum, wie der Widerstand arbeitet, solange er den Spezifikationen entspricht. Er muß nicht hinter die Funktionsweise schauen, um ihn für seinen Entwurf zu verwenden.
Die Eigenschaft, eine eigenständige Einheit zu sein, wird auch Kapselung genannt. Mit der Kapselung können Daten verborgen werden - ein hochgeschätztes Charakteristikum eines Objekts, das genutzt werden kann, ohne daß der Benutzer die internen Arbeitsabläufe kennen muß. Genauso wie Sie einen Kühlschrank benutzen können, ohne davon Ahnung haben zu müssen, wie der Kompressor funktioniert, können Sie ein gut entworfenes Objekt verwenden, ohne etwas über dessen interne Datenelemente zu wissen.
Gleichermaßen muß der Elektroniker im Falle des Widerstandes keine Ahnung vom internen Status des Widerstandes haben. Alle Eigenschaften des Widerstandes sind im Widerstand-Objekt verkapselt und nicht über die elektronische Schaltung verteilt. Einen Widerstand kann man effektiv einsetzen, ohne mit seinen internen Abläufen vertraut zu sein. Seine Daten sind in seinem Gehäuse verborgen.
C++ unterstützt die Kapselung auf dem Weg über spezielle benutzerdefinierte Typen, die sogenannten Klassen. Wie man eine Klasse erzeugt, erfahren Sie in Kapitel 6, »Klassen«. Eine einmal definierte Klasse agiert als vollständig gekapselte Einheit und wird als Ganzheit verwendet. Die eigentliche innere Funktionsweise der Klasse sollte nicht sichtbar sein. Die Benutzer einer gut konzipierten Klasse müssen nicht wissen, wie die Klasse funktioniert, sie müssen nur wissen, wie man sie verwendet.
Wenn die Ingenieure bei Acme Motors ein neues Auto bauen wollen, haben Sie zwei Möglichkeiten: Sie können ein vollständig neues Modell entwickeln oder auf ein vorhandenes Modell aufbauen. So ist vielleicht Ihr Modell Star so gut wie perfekt, aber es soll jetzt eine Ausführung mit Turbolader und 6-Gang-Getriebe geben. Der Chefingenieur könnte es vorziehen, nicht ganz von vorn zu beginnen, und trifft die Entscheidung, einen neuen Star zu bauen, der um die zusätzlichen Features ergänzt wird. Und um dieses Auto vom Star-Modell abzuheben, wird es Quasar genannt. Ein Quasar ist eine Art Stern, der ganz spezielle neue Eigenschaften aufweist.
C++ unterstützt den Grundgedanken der Vererbung. Man kann einen neuen Typ deklarieren, der eine Erweiterung eines vorhandenen Typs darstellt. Man sagt, daß diese neue Unterklasse von einem vorhandenen Typ abgeleitet ist und spricht auch von einem abgeleiteten Typ. Der Quasar wird vom Star abgeleitet und erbt damit dessen gesamte Eigenschaften. Bei Bedarf kann man aber neue hinzufügen. Auf die Vererbung und ihre Anwendung in C++ gehen Kapitel 11, »Vererbung«, und Kapitel 15, »Vererbung - weiterführende Themen«, ein.
Vielleicht reagiert der neue Quasar anders als ein Star, wenn Sie das Gaspedal treten. Der Quasar läuft mit Benzineinspritzung und einem Turbolader, während der Star lediglich Benzin in den Vergaser leitet. Der Fahrer muß von diesen Einzelheiten nichts wissen. Er braucht lediglich das Gaspedal »durchzutreten« und je nach Auto werden die richtigen Mechanismen in Bewegung gesetzt.
C++ unterstützt den Gedanken, daß verschiedene Objekte »genau das Richtige tun«, durch die sogenannte Funktionspolymorphie oder Klassenpolymorphie. Das aus dem Griechischen stammende Wort »polymorph« bedeutet »vielgestaltig«. Polymorphie bezieht sich also darauf, daß man einen Namen für mehrere Formen verwendet. Näheres dazu finden Sie in den Kapiteln 10, »Funktionen - weiterführende Themen«, und 13, »Polymorphie«.
Als sich die objektorientierte Methodik bei Analyse, Entwurf und Programmierung durchzusetzen begann, nahm Bjarne Stroustrup die populärste Sprache für die kommerzielle Software-Entwicklung, C, und erweiterte sie um Merkmale der objektorientierten Programmierung.
Es stimmt zwar, daß C++ eine Obermenge von C ist und daß scheinbar jedes gültige C-Programm auch ein gültiges C++-Programm ist, doch der Sprung von C zu C++ ist größer als er scheint. C++ profitierte jahrelang von der Verwandtschaft zu C, da C- Programmierer bequem auf C++ umsteigen konnten. Viele Programmierer stellten jedoch fest, daß sie für eine umfassende Nutzung aller von C++ gebotenen Möglichkeiten viel Bekanntes vergessen und neue Konzepte und Programmlösungen erlernen mußten.
Es drängt sich die Frage auf: »Soll ich zuerst C lernen, weil C++ eine Obermenge von C ist?« Stroustrup und die meisten C++-Programmierer stimmen überein: Es ist nicht nur nicht erforderlich, zuerst C zu lernen, sondern auch eine schlechte Empfehlung.
Dieses Buch geht davon aus, daß Sie kein C-Programmierer sind. Andernfalls wäre das auch kein Problem. Lesen Sie die ersten Kapitel als Wiederholung, und legen Sie sich dann richtig ins Zeug. Mit Kapitel 6, »Klassen«, steigen wir dann so richtig in die objektorientierte Programmierung ein.
C++ ist heute die am weitesten verbreitete Programmiersprache, zur Erstellung kommerzieller Software entwickelt. In den letzten Jahren wurde diese Vormachtstellung durch Java bedroht, doch inzwischen schwingt das Pendel wieder zurück, und viele Programmierer, die von C++ zu Java gewechselt haben, sind inzwischen wieder auf C++ zurückgekommen. So viel läßt sich jedenfalls feststellen: Die beiden Sprachen sind sich so ähnlich, daß, wer eine Sprache beherrscht, fast 90 % der anderen damit abdeckt.
Das Accredited Standards Committee, das dem American National Standards Institute (amerikanisches Normungsinstitut) unterstellt ist, hat einen internationalen Standard für C++ aufgesetzt.
Der C++-Standard wird inzwischen auch als ISO-Standard (International Standards Organization), NCITS-Standard (National Committee for Information Technology Standards), X3-Standard (alter Name für NCITS) und als ANSI/ISO-Standard bezeichnet. In diesem Buch wird vom ANSI-Standardcode gesprochen, da dies der geläufigste Begriff ist.
Der ANSI-Standard versucht sicherzustellen, daß C++ portierbar ist. Damit soll zum Beispiel garantiert werden, daß Code, der in Übereinstimmung mit dem ANSI-Standard für einen Microsoft-Compiler aufgesetzt wurde, auch ohne Fehler mit einem Compiler eines beliebigen Drittanbieters kompiliert werden kann. Da der Code dieses Buches ebenfalls dem ANSI-Standard folgt, sollten sich die Beispiele fehlerfrei auf einem Mac-, einem Windows- oder einem Alpha-PC kompilieren lassen.
Die meisten, die C++ erlernen, werden den ANSI-Standard nicht wahrnehmen. Schon seit einiger Zeit ist der ANSI-Standard recht stabil und alle größeren Hersteller unterstützen ihn. Wir haben uns bemüht, alle Codebeispiele in diesem Buch auf den ANSI-Standard hin auszurichten.
In C++ ist wichtig, wichtiger vielleicht als in anderen Sprachen, daß der Programmierer das Programm entwirft, bevor er es niederschreibt. Triviale Probleme, wie etwa die in den ersten Kapiteln dieses Buches behandelten, erfordern kaum Entwurfsarbeit. Allerdings ist ein Entwurf bei komplexen Problemen, die die professionellen Programmierer alltäglich herausfordern, unumgänglich. Je gründlicher der Entwurf, desto wahrscheinlicher stellt das Programm für die vorgesehenen Aufgaben eine Lösung dar - sowohl im zeitlichen als auch im finanziellen Rahmen. Ein guter Entwurf führt auch zu einem relativ fehlerfreien und leicht zu wartenden Programm. Man schätzt, daß sich 90 % der Software-Kosten aus Fehlersuche und Wartung zusammensetzen. Ein guter Entwurf hat damit bedeutenden Einfluß auf die Senkung der Gesamtkosten des Projekts.
Bei der Vorbereitung auf den Programmentwurf ist zuerst die Frage zu beantworten: »Welches Problem versuche ich zu lösen?« Jedes Programm sollte ein klares, gut formuliertes Ziel besitzen. Sogar bei den einfachsten Programmen in diesem Buch begegnen Sie diesem Ansatz.
Die zweite Frage für jeden guten Programmierer ist: »Kann man das Ziel erreichen, ohne benutzerspezifische Software schreiben zu müssen?« Die Wiederverwendung und Anpassung vorhandener Programme oder der Kauf von konfektionierter Software sind oft bessere Lösungen für ein Problem als etwas Neues zu schreiben. Der Programmierer, der diese Alternativen zu bieten hat, wird niemals arbeitslos; durch die Entwicklung kostengünstiger Lösungen für aktuelle Probleme ergeben sich fast immer neue Möglichkeiten für die Zukunft.
Hat man das Problem erfaßt und ist das Schreiben eines neuen Programms unumgänglich, kann man mit dem Entwurf beginnen.
Der Prozeß, das Problem voll zu erfassen (Analyse) und mit einer Lösung (Entwurf) aufzuwarten, ist die notwendige Grundlage, um eine kommerzielle Anwendung von Weltklasse zu schreiben.
Doch auch wenn die Schritte, das Problem zu erfassen und eine Lösung zu entwerfen, vor dem eigentlichen Aufsetzen des Codes stehen, ist es ratsamer, sich mit der grundlegenden Syntax und Semantik von C++ vertraut zu machen, bevor man sich den formalen Analyse- und Entwurfstechniken widmet.
Dieses Buch geht von der Annahme aus, daß Ihr Compiler über einen Modus verfügt, mit dem man direkt auf den Bildschirm schreiben kann, ohne erst lang Gedanken an eine Graphik-Umgebung wie in Windows oder auf dem Macintosh zu verlieren. Halten Sie Ausschau nach einer Option wie Konsolen- oder Textbildschirmanwendung, oder schauen Sie in Ihren Compiler-Handbüchern nach.
Möglicherweise verfügt Ihr Compiler über einen eigenen Editor, oder Sie verwenden
einen kommerziellen Texteditor oder eine Textverarbeitung, die Textdateien erzeugen
kann. Mit welchem Werkzeug Sie Ihr Programm auch erstellen, es muß reine Textdateien
ohne eingebettete Steuerbefehle liefern. Beispiele für »sichere« Editoren sind der
zu Windows gehörende Editor Notepad, der über den DOS-Befehl Edit
aufrufbare
Editor, Brief, Epsilon, EMACS und vi. Kommerzielle Textverarbeitungen wie WordPerfect,
Word und Dutzende andere bieten ebenfalls die Möglichkeit, das Dokument
als einfache Textdatei zu speichern.
Die Dateien, die Sie mit Ihrem Editor erstellen, bezeichnet man als Quelldateien. Normalerweise
erhalten diese Dateien unter C++ die Dateierweiterung .CPP
, .CP
oder .C
.
In diesem Buch sind alle Quellcodedateien einheitlich mit der Erweiterung .CPP
versehen.
Prüfen Sie bitte, welche Erweiterungen Ihr Compiler benötigt.
Bei den meisten C++-Compilern hat die Erweiterung der Quelldateien keine besondere Bedeutung. Gibt man allerdings keine Erweiterung explizit an, verwenden viele Compiler per Vorgabe die Erweiterung
.CPP
. Seien Sie jedoch mit der Verwendung.C
vorsichtig, da einige Compiler davon ausgehen, daß es sich bei.C
-Dateien um C-Code und bei.CPP
-Dateien um C++ handelt. Auch hier möchte ich Ihnen nahelegen, einen Blick in Ihre Handbücher zu werfen.
Obwohl der Quellcode in Ihrer Datei etwas kryptisch aussieht und jeder, der sich mit C++ nicht auskennt, kaum versteht, für was das ganze gut ist, haben wir es trotzdem mit einer für den Menschen verständlichen Form zu tun. Die Quellcodedatei ist kein Programm und läßt sich auch nicht wie ein Programm ausführen.
Um aus dem Quellcode ein Programm zu machen, verwendet man einen Compiler. Wie man den Compiler aufruft und ihm den Standort der Quelldatei angibt, ist vom konkreten Compiler abhängig. Sehen Sie dazu in der entsprechenden Dokumentation nach.
Durch das Kompilieren des Quellcodes entsteht eine sogenannte Objektdatei (in der
Regel mit der Erweiterung .OBJ
). Allerdings handelt es sich auch hier noch nicht um
ein ausführbares Programm. Um aus der Objektdatei ein ausführbares Programm zu
erstellen, ruft man den Linker auf.
C++-Programme werden in der Regel durch das Verbinden (Linken) einer oder mehrerer Objektdateien mit einer oder mehreren Bibliotheken erzeugt. Unter einer Bibliothek versteht man eine Sammlung von Dateien, die vom Linker direkt in ein Programm mit eingebunden werden können. Bibliotheken erwirbt man automatisch zusammen mit dem Compiler, man kauft sie extra dazu oder man erzeugt und kompiliert sie selbst. Zu allen C++-Compilern gehört eine Bibliothek nützlicher Funktionen und Klassen, die Sie in Ihr Programm aufnehmen können. Eine Funktion ist ein Codeblock, der eine bestimmte Aufgabe realisiert, beispielsweise das Addieren zweier Zahlen oder die Ausgabe auf den Bildschirm. Unter einer Klasse versteht man eine Sammlung von Daten und verwandten Funktionen. Auf Funktionen und Klassen gehen wir ab Kapitel 5 noch näher ein.
Eine ausführbare Datei erzeugt man in folgenden Schritten:
Wenn jedes Programm sofort beim ersten Ausprobieren funktionieren würde, hätten wir es mit folgendem vollständigen Entwicklungszyklus zu tun: Schreiben des Programms, Kompilieren des Quellcodes, Linken des Programms und Ausführen des Programms. Leider enthält fast jedes Programm irgendwelche Fehler - sogenannte Bugs - auch wenn sie manchmal nur trivial sind. Einige Bugs verhindern bereits das Kompilieren, bei manchen Fehlern kann man das Programm nicht linken, und einige Fehler zeigen sich erst bei der Ausführung des Programms.
Welchen Fehler Sie auch finden, er ist zu beseitigen. Und dazu gehört die Bearbeitung des Quellcodes, das erneute Kompilieren und Linken und schließlich ein neuer Start des Programms. Abbildung 1.1 zeigt diesen Zyklus mit einer Darstellung der einzelnen Schritte.
Abbildung 1.1: Die Schritte im Entwicklungsprozeß eines C++-Programms
Es ist schon Tradition, daß ein Programmierbuch mit einem Programm beginnt, das
die Worte Hello World
auf den Bildschirm bringt oder eine ähnliche Aufgabe realisiert.
Auch wir bleiben dieser Tradition treu.
Tippen Sie das erste Programm direkt in Ihren Editor - genau wie dargestellt - ein.
Nachdem Sie den Quellcode kritisch durchgesehen haben, speichern Sie die Datei,
kompilieren sie, linken sie und führen sie aus. Auf dem Bildschirm erscheinen die
Worte Hello World
. Kümmern Sie sich momentan noch nicht darum, wie das Ganze
funktioniert, das Programm soll Sie nur mit dem Entwicklungszyklus vertraut machen.
Die einzelnen Aspekte dieses Programms sind Gegenstand der nächsten Lektionen.
Das folgende Listing enthält an der linken Seite Zeilennummern. Diese dienen lediglich der Bezugnahme in diesem Buch und sind nicht als Teil des Quellcodes im Editor einzugeben. Beispielsweise geben Sie die Zeile 1 von Listing 1.1 in der folgenden Form ein:
Listing 1.1: HELLO.CPP, das Programm Hello World
1: #include <iostream.h>
2:
3: int main()
4: {
5: cout << "Hello World!\n";
6: return 0;
7: }
Vergewissern Sie sich, daß alles exakt wie dargestellt eingegeben wurde. Achten Sie
insbesondere auf die Satzzeichen. Das Symbol <<
in Zeile 5 ist ein Umleitungssymbol,
das man auf deutschen Tastaturen rechts neben der linken Umschalt-Taste findet. Zeile
5 endet mit einem Semikolon, das auf keinen Fall fehlen darf!
Prüfen Sie auch, ob die Compiler-Direktiven entsprechend eingestellt sind. Die meisten
Compiler linken automatisch. Trotzdem sollten Sie in der Dokumentation nachsehen.
Wenn Sie Fehler erhalten, überprüfen Sie zunächst sorgfältig den eingegebenen
Code und suchen nach Abweichungen von Listing 1.1. Wenn Sie einen Fehler zu
Zeile 1 erhalten, wie etwa Include-Datei kann nicht geoeffnet werden: 'iostream.h'...
, sollten Sie sich in der Dokumentation zu Ihrem Compiler über die Einstellungen
für den Include-Pfad und die Umgebungsvariablen informieren. Wenn Sie einen
Fehler erhalten, daß es keinen Prototyp für main
gibt, fügen Sie die Zeile int
main();
unmittelbar vor Zeile 3 ein. Diese Zeile müssen Sie jedem Programm in diesem
Buch vor Beginn der Funktion main()
hinzufügen. Viele Compiler kommen ohne
aus, bei einigen aber ist es erforderlich.
Das fertige Programm sieht folgendermaßen aus:
1: #include <iostream.h>
2: int main(); // die meisten Compiler kommen ohne
3: // diese Zeile aus
4: int main() {
5: {
6: cout << "Hello World!\n";
7: return 0;
8: }
Führen Sie nun Hello.exe
aus. Auf dem Bildschirm sollte der Text
Hello World!
erscheinen. Sollte das so sein, Gratulation! Sie haben gerade Ihr erstes C++-Programm eingegeben, kompiliert und ausgeführt. Es ist vielleicht nicht gerade berauschend, aber nahezu jeder professionelle C++-Programmierer hat genau mit diesem Programm begonnen.
Einsatz der Standardbibliotheken
Um sicherzustellen, daß Leser mit älteren Compilern keine Schwierigkeiten mit dem Code dieses Buches haben, verwenden wir die älteren
include
-Dateien. So finden Sie#include <iostream.h>anstelle der neuen Header-Dateien der Standardbibliotheken
#include <iostream>Dies sollte auf allen Compilern funktionieren und hat nur geringfügige Nachteile. Ziehen Sie es jedoch vor, die Bibliotheken des neuen Standards zu verwenden, ändern Sie Ihren Code einfach in
#include <iostream>using namespace std;direkt unter Ihre Liste der
include
-Dateien. Das weiterführende Thema der Namensbereiche wird noch eingehender in Kapitel 17 besprochen.Ob Sie jetzt Standard-Headerdateien verwenden oder nicht, sollte die Ausführung des Codes in diesem Buch eigentlich nicht betreffen. Der wichtigste Unterschied zwischen den älteren Bibliotheken und der neuen Standardbibliothek ist die
iostream-
Bibliothek (die Beschreibung finden Sie in Kapitel 16). Doch auch diese Änderungen haben keinen Einfluß auf den Code in diesem Buch. Die Änderungen sind nur geringfügig und nur für Eingeweihte; zumindest gehen Sie weit über den Rahmen eines Anfängerhandbuchs hinaus.
Alle Programme dieses Buchs wurden mit dem Visual C++ 6-Compiler getestet und sollten sich mit allen Visual C++-Compilern von Microsoft ab 4.0 und höher problemlos kompilieren, linken und ausführen lassen. Theoretisch sollten sich die Programme dieses Buchs, da der Code dem ANSI-Standard entspricht, auf allen Compilern auf dem Markt ausführen lassen.
In der Theorie sind Theorie und Praxis eins. In der Praxis jedoch nie.
Für Ihre ersten Schritte soll Sie dieser kurze Abschnitt darin einführen, wie Sie ein Programm mit dem Microsoft-Compiler bearbeiten, kompilieren, linken und ausführen. Wenn Sie einen anderen Compiler verwenden, können die Schritte leicht von den hier beschriebenen abweichen. Aber auch wenn Sie Microsofts Visual C++ 6- Compiler benutzen, lesen Sie in Ihrer Dokumentation nach, wie Ihre Schritte ab hier aussehen.
Gehen Sie wie folgt vor, um das Programm Hello World zu erstellen und zu testen:
Fehler zur Kompilierzeit können verschiedenste Ursachen haben. Gewöhnlich sind sie das Ergebnis eines Schreibfehlers oder einer anderen Nachlässigkeit. Gute Compiler weisen nicht nur darauf hin, was Sie falsch gemacht haben, sie zeigen genau die Stelle im Code an, wo der Fehler aufgetreten ist. Die besten Compiler schlagen sogar eine Lösung vor!
Einen Compiler-Fehler können Sie sich in der Praxis ansehen, indem Sie absichtlich
einen Fehler in das Programm einbauen. Nachdem Sie Hello.cpp
erst einmal richtig
zum Laufen gebracht haben, bearbeiten Sie nun die Quelldatei und entfernen die
schließende Klammer auf Zeile 7. Das Programm entspricht nun Listing 1.2.
Listing 1.2: Demonstration eines Compiler-Fehlers
1: #include <iostream.h>
2:
3: int main()
4: {
5: cout << "Hello World!\n";
6: return 0;
Kompilieren Sie Ihr Programm erneut. Es sollte nun die folgende Fehlermeldung erscheinen:
****Hello.cpp, line 5: Compound statement missing terminating }
in function main().
F:\Mcp\Tycpp21d\Testing\List0101.cpp(8) : fatal error C1004:
unexpected end of file found
Error executing cl.exe.
}
Diese Fehlermeldung teilt Ihnen die problematische Datei und die Zeilennummer mit
und um welches Problem es sich handelt. (Zugegebenermaßen sieht das ganze etwas
kryptisch aus.) Beachten Sie, daß die Fehlermeldung auf Zeile 5 verweist. Der Compiler
war sich nicht sicher, ob Sie die schließende Klammer vor oder nach der cout
-Anweisung
in Zeile 5 setzen möchten. Manchmal bezieht sich die Fehlermeldung auf die
unmittelbare Nachbarschaft des Problems. Könnte ein Compiler jedes Problem perfekt
identifizieren, könnte er den Code auch selbst von Fehlern bereinigen.
Nach dem Studium dieses Kapitels sollten Sie einen Überblick haben, wie sich C++ entwickelt hat und für welche Art von Problemlösungen diese Sprache geschaffen wurde. Sie sollten sich bestärkt fühlen, daß das Erlernen von C++ die richtige Wahl für jeden an der Programmierung Interessierten im nächsten Jahrzehnt ist. C++ stellt die Werkzeuge der objektorientierten Programmierung und die Leistung einer systemnahen Sprache zur Verfügung, was C++ zur bevorzugten Entwicklungssprache macht.
In diesem ganz am Anfang stehenden Kapitel haben Sie gelernt, wie Sie Ihr erstes C++-Programm schreiben, kompilieren, linken und ausführen, und wie der normale Entwicklungszyklus aussieht. Außerdem haben Sie sich ein wenig mit dem Grundanliegen der objektorientierten Programmierung vertraut gemacht. Zu diesen Themen kehren Sie während der restlichen Unterrichtsstunden zurück.
Frage:
Worin besteht der Unterschied zwischen einem Texteditor und einer
Textverarbeitung?
Antwort:
Ein Texteditor erzeugt Dateien, die aus reinem Text bestehen und keinerlei
Formatierungsbefehle oder andere spezielle Symbole, wie sie für eine Textverarbeitung
erforderlich sind, enthalten. Bei reinen Textdateien gibt es keinen
automatischen Zeilenumbruch, keinen Fettdruck, keine kursive Zeichen usw.
Frage:
Mein Compiler verfügt über einen integrierten Editor. Ist das das geeignete
Werkzeug?
Antwort:
Fast alle Compiler sind in der Lage, den von beliebigen Texteditoren erzeugten
Code zu kompilieren. Der Vorteil des integrierten Editors besteht allerdings
darin, daß man gegebenenfalls schnell zwischen den Entwicklungsschritten
Editieren und Kompilieren hin- und herschalten kann. Zu modernen
Compilern gehört eine integrierte Entwicklungsumgebung, die dem Programmierer
den Zugriff auf Hilfedateien, die Bearbeitung und das Kompilieren des
Codes unmittelbar erlaubt. Außerdem lassen sich hier Compiler- und Linker-
Fehler beseitigen, ohne daß man die Umgebung verlassen muß.
Frage:
Kann ich Warnungen des Compilers ignorieren?
Antwort:
Auf keinen Fall. Machen Sie es sich zur Angewohnheit, Warnungen als Fehler
zu behandeln. C++ verwendet den Compiler, um Sie vor etwas zu warnen,
das Sie möglicherweise gar nicht beabsichtigen. Unternehmen Sie die erforderlichen
Schritte, damit diese Warnungen nicht wieder auftreten.
Frage:
Was versteht man unter der Kompilierzeit?
Antwort:
Die Kompilierzeit ist die Phase im Entwicklungszyklus, zu der man den Compiler
ausführt. Weitere Phasen sind die Linkzeit (wenn man den Objektcode
mit dem Linker verknüpft) oder die Laufzeit (wenn man das Programm ausführt).
Damit differenziert der Programmierer die drei Zeitabschnitte, in denen
Fehler normalerweise zutage treten.
Der Workshop enthält Quizfragen, die Ihnen helfen sollen, Ihr Wissen zu festigen, und Übungen, die Sie anregen sollen, das eben Gelernte umzusetzen und eigene Erfahrungen zu sammeln. Versuchen Sie, das Quiz und die Übungen zu beantworten und zu verstehen, bevor Sie die Lösungen in Anhang D lesen und zur Lektion des nächsten Tages übergehen.
1: #include <iostream.h>
2: int main()
3: {
4: int x = 5;
5: int y = 7;
6: cout << "\n";
7: cout << x + y << " " << x * y;
8: cout << "\n";
9: return 0;
10:}
1: include <iostream.h>
2: int main()
3: {
4: cout << "Hello World\n";
5: return 0;
6: }
© Markt&Technik Verlag, ein Imprint der Pearson Education Deutschland GmbH