Einführung in C++ Kapitel 6 — Mehr über Zugriffsschutz

Wozu das Ganze?

Wir haben uns diese Frage schon früher gestellt, können aber jetzt, da wir ein wenig Erfahrung gesammelt haben, eine wesentlich bessere Antwort geben. Zugriffsschutz schützt die Daten — wie der Name schon sagt — vor irrtümlicher Änderung, und Konstruktoren stellen sicher, daß alle Elemente initialisiert werden. Beide verhindern Fehler, die wir gerne machen. Während wir eine Klasse schreiben, beschäftigen wir uns nur mit den Interna der Klasse, später, wenn wir die Klasse dann wirklich anwenden, brauchen wir uns um die interne Struktur der Klasse oder ihrer Methoden nicht mehr zu kümmern und können uns auf die Lösung des Problems konzentrieren. Natürlich gibt es noch viel über die Verwendung und die Vorteile von Klassen zu sagen und zu lernen, weshalb wir uns auch gleich einigen neuen Aspekten widmen wollen.

Ziel dieses Kapitels ist es, zu illustrieren, wie einige der traditionellen Aspekte von C/C++ mit Klassen und Objekten verwendet werden. Wir werden über Zeiger auf ein Objekt und Zeiger innerhalb eines Objektes sprechen, von Arrays, die in einem Objekt liegen und Arrays von Objekten. Da Objekte nur ein weiteres "Datenkonstrukt" in C++ sind, ist all das vorher Genannte möglich und kann verwendet werden, wenn der Bedarf besteht.

Um das ganze zumindest ein bißchen systematisch zu gestalten, werden wir das Programm BOXEN1.CPP als Ausgangspunkt nehmen und mit jedem Beispielprogramm einige wenige neue Konstrukte hinzufügen. Du erinnerst Dich sicherlich, daß es sich bei BOXEN1.CPP um ein sehr einfaches Programm gehandelt hat, mit der Definition der Klasse, der Implementation derselben und dem Hauptprogramm in einer einzelnen Datei. Wir nehmen diese Datei als Basis, weil wir nach und nach alle Teile des Programmes ändern werden und es daher anschaulicher ist, all das in einer einzigen Datei zu haben. Es sollte aber klar sein, daß es richtiger wäre, die Teile auf drei verschiedene Dateien aufzuteilen, wie wir es mit BOX.H, BOX.CPP und BOXEN2.CPP im vorigen Kapitel gezeigt haben. Das erlaubt es der Autorin von Box, der Programmiererin nur die Schnittstelle, BOX.H, zur Verfügung zu stellen. Wie wir schon des öfteren festgestellt haben, erscheint es eigentümlich, so kleine Programme auf drei Dateien aufzuteilen und das ist es ja auch. Das letzte Kapitel dieser Einführung wird ein Programm vorstellen, das diese Aufteilung auch rechtfertigt.

Ein Array von Objekten in C++

Beispielprogramm: OBJARRAY.CPP

Die Datei OBJARRAY.CPP ist unser erstes Beispiel eines Arrays von Objekten. Dieses Beispielprogramm ist nahezu identisch mit dem Programm BOXEN1.CPP bis zur Zeile 45, wo wir einen Array von 4 Boxen definieren.

Wenn Du daran denkst, welche Funktion ein Konstruktor hat, erinnerst Du Dich sicherlich, daß jedes der Box Objekte mit den im Konstruktor angegebenen Werten initialisiert wird, da der Konstruktor für jedes einzelne Objekt bei der Definition aufgerufen wird. Um einen Array von Objekten definieren zu können, muß ein Konstruktor ohne Parameter für dieses Objekt existieren. (Wir haben noch nicht gezeigt, wie ein Konstruktor mit Initialisierungsparametern aussieht, werden das aber im nächsten Programm tun.) Das ist eine Frage der Effizienz, da es möglicherweise eine Fehler ist, alle Elemente eines Arrays von Objekten mit denselben Werten zu initialisieren. Wir werden das Ergebnis, das der Aufruf des Konstruktors liefert, sehen, wenn wir das Programm kompilieren und ausführen.

In Zeile 50 starten wir eine for-Schleife, die mit 1 anstelle der für das Element eines Arrays typischen 0 beginnt. Damit verwendet das erste Objekt, Gruppe[0], die Werte, die ihm bei der Ausführung des Konstruktors zugewiesen wurden. Das Senden einer Nachricht an eines der Objekte erfolgt genauso wie bei jedem anderen Objekt auch. Wir verwenden dazu den Namen des Arrays, gefolgt vom Index des Objektes in eckigen Klammern, wie in Zeile 51 gezeigt. Die andere Methode rufen wir in den Zeilen 58 und 59 auf, wo die Fläche der vier Boxen der Gruppe am Bildschirm ausgegeben wird.

Deklaration und Definition einer Variaben in C++

Zu Illustrationszwecken haben wir in Zeile 8 noch eine Variable, ExtraDaten hinzugefügt. Da wir das Schlüsselwort static verwenden, handelt es sich dabei um eine externe Variable und es existiert nur eine Variable für alle Objekte der Klasse. Alle sieben Objekte dieser Klasse teilen sich also diese eine Variable.

Die Variable wird hier lediglich deklariert, was heißt, daß sie einmal existieren wird, sie wird aber noch nicht definiert. Eine Deklaration sagt dem Compiler, daß irgendwo im Programm eine Variable existieren wird und gibt ihr einen Namen, aber es ist die Definition, die im Speicher einen Platz für die Variable bereitstellt. Per Definitionem kann eine statische Variable im Kopf einer Klasse deklariert, nicht aber definiert werden. Sie wird also in der Implementation definiert, in unserem Fall in Zeile 17 und kann dann innerhalb der Klasse verwendet werden.

Bild 6-1 versinnbildlicht einige der Variablen. Die Objekte mit den Namen Grosz, Gruppe[0], Gruppe[1] und Gruppe[2] sind auf dem Bild nicht zu sehen, aber auch sie teilen sich mit den anderen die Variable ExtraDaten. Sie werden im Bild nicht gezeigt, um es ein wenig übersichtlicher und klarer zu gestalten. Jedes Objekt hat seine eigene Laenge und Breitey, da diese nicht als static deklariert sind.

Abbildung 6.1

Die Zeile 24 des Konstruktors setzt die globale Variable mit jedem Objekt, das wir erzeugen, auf 1. Es ist nur eine Zuweisung vonnöten, die anderen sechs sind unnötig. Es ist im Allgemeinen keine gute Idee, einer statischen Variable in einem Konstruktor einen Wert zuzuweisen, in diesem Fall aber illustriert das eine Variable, die als static deklariert ist. Um zu zeigen, das es wirklich nur eine solche Variable gibt, die sich alle Objekte der Klasse teilen, inkrementiert die Methode, die sie liest, die Variable auch. Jedes Mal, wenn wir sie in den Zeilen 61 bis 65 lesen, wird sie um 1 erweitert, und das Ergebnis beweist uns, daß es sich bei dieser Variable wirklich um ein Einzelstück handelt. Du wirst auch bemerken, daß die Methode mit dem Namen HoleExtraDaten innerhalb der Klassendeklaration definiert und daher als inline-Code behandelt wird.

Einführung in C++ bringt Dich in Partnerschaft mit Amazon.de von Null auf Programmieren in ein paar Klicks.

Zum Beispiel variabel bleiben:

Design Patterns: Entwurfsmuster als Elemente wiederverwendbarer objektorientierter Software (mitp Professional)
Programmieren ist Problemlösen. Dieser Klassiker hilft dabei und hat Antworten auf die Fragen, die mit "Wie mache ich...?" beginnen.
›› Mehr Softwareentwicklung-Bücher

Du wirst Dich an die beiden statischen Variablen, die wir in den Zeilen 18 und 19 der Datei DATUM.H des Kapitels 5 deklariert haben, erinnern. In Zeile 9 und 10 von DATUM.CPP haben wir sie definiert und gesagt, daß wir uns ihnen später widmen werden. Deklaration und Definition dieser Variablen sind ein gutes Beispiel dafür, wo diese Konstrukte für statische Variablen in Deinem Code stehen sollten.

Wenn Du sicher bist, daß Du dieses Beispielprogramm und vor allem Funktion und Verwendung von statischen Variablen verstanden hast, kompiliere es und führe es aus.

Eine Zeichenkette innerhalb eines C++ Objektes

Beispielprogramm: OBJZKETT.CPP

Das Programm OBJZKETT.CPP ist unser erstes Beispiel für eine Zeichenkette innerhalb eines Objektes. Eigentlich handelt es sich dabei ja nicht um eine Zeichenkette selbst, sondern um einen Zeiger, die beiden sind aber so eng verbunden, daß wir sie zugleich abhandeln können.

In Zeile 8 deklarieren wir einen Zeiger auf eine Variable vom Typ char mit dem Namen TextZeile Der Konstruktor nimmt einen Parameter, einen Zeiger auf eine Zeichenkette, entgegen. Die Zeichenkette wird im Konstruktor unter dem Namen TextZeile kopiert. Wir hätten die Variable TextZeile in der Klasse als Array deklarieren können, um dann mithilfe von strcpy() die Zeichenkette in diesen Array zu kopieren und alles hätte genauso gut funktioniert. Das soll aber Dir als Aufgabe am Ende des Kapitels vorbehalten bleiben [hehe]. Wir sollten vielleicht noch festhalten, daß wir uns keineswegs auf einen einzigen Parameter für einen Konstruktor beschränken müssen. Wie wir noch zeigen werden, kann ein Konstruktor (fast) jede erdenkliche Anzahl von Parametern haben.

Wenn wir also dieses Mal unsere drei Boxen deklarieren geben wir jeder eine konstante Zeichenkette mit auf den Weg zum Konstruktor, damit dieser dem internen Zeiger auf eine Zeichenkette auch etwas zuweisen kann. Beim Aufruf von HoleFlaeche() in den Zeilen 50 bis 54 wird eine Nachricht ausgegeben und die Fläche zurückgegeben. Es wäre sicherlich sinnvoller, diese beiden Aktionen auf separate Methoden aufzuteilen, da ja kein ersichtlicher Zusammenhang zwischen ihnen besteht, wir haben es aber so gemacht wie wir es gemacht haben, um zu zeigen, daß es geht. Was wir also wirklich demonstrieren, ist, daß eine Methode einen Nebeneffekt (Ausgabe der Nachricht) haben kann und einen Wert zurückgibt, die Fläche der Box. We wir aber in Kapitel 4 beim Beispiel STANDARD.CPP gesehen haben, ist die Abfolge der Abarbeitung bisweilen eigenartig was, uns dazu bewogen hat, die Codezeile auf zwei aufzuteilen.

Hast Du dieses Programm verstanden, kompiliere es und führe es aus.

Ein C++ Objekt mit einem internen Zeiger

Beispielprogramm: OBJINTZG.CPP

Das Programm OBJINTZG.CPP ist unser erstes Beispiel für ein Programm mit eingebettetem Zeiger, mit dem wir dynamisch Speicher beschaffen.

In Zeile 8 deklarieren wir einen Zeiger auf eine Variable vom Typ int, aber es ist eben nur ein Zeiger, kein Speicher ist ihm tatsächlich noch zugewiesen. Deshalb stellt der Konstruktor in Zeile 22 eine Variable vom Typ int im Speicher bereit, die wir mit diesem Zeiger verwenden. Es ist Dir sicherlich klar, daß jedes der drei Objekte, die wir in Zeile 46 definieren, seinen eigenen Zeiger hat, der auf seine eigene Adresse im Speicher zeigt. Für jedes Objekt steht eine eigene dynamisch beschaffte Variable im Speicher zur Verfügung. Alle diese Variablen haben aber zunächst den Wert 112, da wir in Zeile 23 diesen Wert in jeder der drei Variablen speichern, je einmal pro Konstruktoraufruf.

In einem so kleinen Programm müssen wir uns schon sehr anstrengen, den verfügbaren Speicher voll auszuschöpfen, und mit dem, was wir tun, wird uns das aller Wahrscheinlichkeit nach auch nicht gelingen. Deshalb führen wir keinen Test durch, ob der Speicher, den wir anfordern, auch tatsächlich verfügbar ist. In einem "richtigen" Programm solltest Du aber testen, ob der Wert des zurückgegebenen Zeigers nicht NULL ist, um sicherzustellen, daß die Daten auch gespeichert werden können.

Die Methode mit dem Namen Setze() erwartet drei Parameter, von denen letzterer den Wert der neuen, dynamisch beschafften Variable setzt. Wir senden Nachrichten, diese Methode auszuführen, an zwei Objekte, die kleine und die große Box. Die Standardwerte der mittleren Box bleiben unangetastet.

Wir zeigen die drei Flächen gefolgt von den drei in der dynamisch beschafften Variable gespeicherten Werten aus und haben schlußendlich ein Programm, das einen Destruktor braucht, um vollkommen richtig zu funktionieren. Wenn wir einfach den Gültigkeitsbereich der Objekte verlassen, wie wir es tun, wenn wir die Funktion main() verlassen, bleiben uns die drei dynamisch beschafften Variablen im Speicher erhalten, nur zeigt nichts mehr auf sie. Sie sind nicht mehr adressierbar und deshalb nichts als verschwendeter Speicherplatz. Aus diesem Grund benötigen wir einen Destruktor, der die Variablen löscht (mittels delete), auf die die Zeiger mit dem bedeutungsschwangeren Namen Zeiger zeigen, je eine pro Aufruf. Bei einem solchen Aufruf (der wie wir wissen automatisch erfolgt, wenn ein Objekt zu existieren aufhört) weisen die Zeilen 38 und 39 den Variablen, die automatisch gelöscht werden, den Wert 0 zu. Zwar ist dies vollkommen sinnlos, möglich ist es aber doch.

In unserem speziellen Beispiel werden alle Variablen (auch die dynamisch beschafften) automatisch gelöscht, da wir zum Betriebssystem zurückkehren, das diese Aufgabe für uns übernimmt, wenn es das komplette Programm aus dem Speicher entfernt. Trotzdem zeugt es von gutem Programmierstil, aufzuräumen, wenn man mit dem Spielen fertig ist (dynamisch bereitgestellten Speicher nicht mehr benötigt).

Einführung in C++ bringt Dich in Partnerschaft mit Amazon.de von Null auf Programmieren in ein paar Klicks.

Zum Beispiel Objekte:

Objektorientierte Programmierung: Das umfassende Handbuch. Lernen Sie die Prinzipien guter Objektorientierung.
Ungefähr alles nicht nur, das man wissen muss, sondern auch, das man wissen kann, in einem Buch. Dabei ist "Objektorientierte Programmierung" nicht unpraktisch und langweilig, nein: voll mit Beispielen und vor allem verständlichen Erklärungen, macht es einen interessiert — und mit brauchbarer objektorientierung zur besseren Programmiererin.
›› Mehr Softwareentwicklung-Bücher

Auf ein anderes Konstrukt sollten wir auch noch einmal kurz eingehen, nämlich auf die Methoden in den Zeilen 12 und 13, die wir inline implementieren. Wie wir in Kapitel 5 festgestellt haben, können Funktionen mit dieser Technik implementiert werden, wenn erstes und oberstes Ziel Geschwindigkeit ist, da die Funktionen im Code selbst stehen und nicht mit einem Funktionsaufruf verbunden sind. Da der Code für diese Methoden in der Deklaration steht, wir der Compiler ihn inline, also im Code, wo der Funktionsaufruf steht einfach an dessen Statt einsetzen, eine weitere Implementation des Codes der Methode ist nicht notwendig. Es handelt sich dabei allerdings nur um einen Vorschlag an den Compiler, das zu tun, er muß sich keineswegs daran halten und kann die Methode (oder Funktion) als solche implementieren.

Bedenke aber, daß wir am Verstecken unseres Codes interessiert sind, was durch die im vorigen Absatz diskutierte Vorgangsweise natürlich untergraben wird, da wir den kompletten Code offen zur Schau stellen. Oft aber wirst Du an der Geschwindigkeit mehr interessiert sein als am Verstecken von trivialem Code, denn nur solcher empfiehlt sich wirklich, inline implementiert zu werden. Kompiliere das Programm und führe es aus.

Ein dynamisch beschafftes Objekt

Beispielprogramm: OBJDYNAM.CPP

Im Beispielprogramm OBJDYNAM.CPP werfen wir zum ersten Mal einen Blick auf ein dynamisch beschafftes Objekt. Dieses unterscheidet sich nicht von einem "normalen" dynamisch bereitgestellten Objekt, ein Beispiel ist aber immer recht hilfreich.

In Zeile 40 definieren wir einen Zeiger auf ein Objekt vom Typ (der Klasse) Box und da es sich nur um einen Zeiger ohne Objekt, auf das er zeigen könnte, handelt, stellen wir in Zeile 45 dynamisch ein solches bereit. Wenn wir das Objekt in Zeile 45 kreieren, wird der Konstruktor automatisch aufgerufen und weist den zwei internen Variablen Werte zu. Der Konstruktor wird nicht aufgerufen, wenn wir den Zeiger definieren, da es ja zu diesem Zeitpunkt nichts gibt, das initialisiert werden könnte. Er wird erst aufgerufen, wenn der Speicher für das Objekt bereitgestellt wird.

Auf die Elemente des Objektes greifen wir so zu wie auch auf die Elemente einer Struktur, mithilfe des Zeigeroperators, wie etwa in den Zeilen 51 bis 53 illustriert. Natürlich kannst Du den Zeiger auch ohne den Pfeil zu verwenden dereferenzieren, wie zum Beispiel (*point).set(12, 12); anstatt des Code in Zeile 52, die Pfeilnotation ist aber einfacher und universeller, sollte also verwendet werden. Schließlich löschen wir das Objekt in Zeile 55 und das Programm ist abgearbeitet. Gäbe es für diese Klasse einen Destruktor, würde er automatisch im Zuge der delete Anweisung aufgerufen werden, um aufzuräumen, bevor das Objekt im Datennirvana eins mit diesem wird. (??)

Du hast mittlerweile wahrscheinlich bemerkt, daß die Verwendung von Objekten sich von der Anwendung von Strukturen nicht wesentlich unterscheidet. Kompiliere dieses Programm und führe es aus, wenn Du verstanden hast, worum es sich dreht.

Ein Objekt mit einem Zeiger auf ein anderes Objekt

Beispielprogramm: OBJLISTE.CPP

Das Programm OBJLISTE.CPP zeigt ein Objekt mit einer internen Referenz auf ein anderes Objekt derselben Klasse. Das ist die normale Struktur einer einfach verbundenen Liste und wir werden die Verwendung in diesem Beispiel sehr einfach halten.

Der Konstruktor beinhaltet in Zeile 22 die Initialisierung des Zeigers mit einer Zuweisung des Wertes NULL. Das solltest Du in allen Deinen Programmen so halten, laß keinen Zeiger ins Nichts zeigen, sondern initialisiere alle Zeiger auf irgendeinen Wert. Wenn dies im Konstruktor geschieht, hast Du gewährleistet, daß die Zeiger eines jeden Objektes automatisch initialisiert werden. Es ist dann unmöglich, es zu vergessen.

In den Zeilen 13 und 14 deklarieren wir zwei weitere Methoden, von denen die in Zeile 14 ein Konstrukt beinhaltet, das wir in unserer Einführung noch nicht betrachtet haben. Diese Methode gibt einen Zeiger auf ein Objekt der Klasse Box zurück. Wie Du weißt, kannst Du in Standard-C eine Zeiger auf eine Struktur zurückgeben, und was wir hier haben, ist die Umsetzung dessen in C++. Die Implementation in den Zeilen 49 bis 52 gibt den Zeiger, der als Elementvariable im Objekt selbst gespeichert ist, zurück. Auf die Verwendung werden wir eingehen, wenn wir das eigentliche Programm betrachten.

Abb. 6.2

Im Hauptprogramm definieren wir einen weiteren Zeiger mit dem Namen BoxZeiger, um ihn später zu verwenden. In Zeile 67 lassen wir den internen Zeiger des Objektes der Klasse Box mit dem Namen Klein auf das Objekt Mittel zeigen. Zeile 68 läßt den internen Zeiger des Objektes Mittel auf das Objekt Grosz zeigen. Wir haben eine verbundene Liste mit drei Elementen erzeugt. In Zeile 70 veranlassen wir, daß der Zeiger des Hauptprogrammes auf das Objekt Klein zeigt. In Zeile 71 verwenden wir diesen Zeiger dann, um auf das Objekt Klein zu zeigen und lassen ihn auf das Objekt zeigen, auf das der Zeiger des Objektes Klein zeigt, also die Adresse des Objektes Mittel. Wir sind demnach von einem Objekt zum nächsten fortgeschritten, indem wir an eines der Objekte eine Nachricht gesendet haben. Würden wir die Zeile 71 genau so wie sie hier steht noch einmal wiederholen, würde das den Zeiger des Hauptprogrammes auf das Objekt Grosz zeigen lassen. Wir hätten dann die gesamte Liste mit ihren drei Elementen durchwandert. Bild 6-2 zeigt den Speicherinhalt nach Abarbeiten der Zeile 70. Beachte, daß nur ein Fragment jedes Objektes dargestellt ist, um die Zeichnung einfach zu halten.

Noch ein neues C++-Schlüsselwort: this

In C++ ist ein neues Schlüsselwort verfügbar: this. Das Wort this ist in jedem Objekt definiert als Zeiger auf das Objekt selbst, in dem dieser enthalten ist. Er ist einfach definiert als:

KlassenName *this;

und wird so initialisiert, daß es auf das Objekt zeigt, für das die Elementfunktion aufgerufen wird. Dieser Zeiger ist natürlich am nützlichsten im Umgang mit anderen Zeigern und da besonders in einer verbundenen Liste wenn Du eine Referenz auf das Element, das Du der Liste gerade hinzufügst, brauchst. Für diesen Zweck ist das Schlüsselwort this verfügbar und kann in jedem Objekt verwendet werden. Eigentlich wäre die "richtige" Art, eine Variable in einer Liste zu verwenden, mittels this->VariablenName, der Compiler nimmt aber implizit an, daß wir den Zeiger verwenden und so können wir das ganze vereinfachen, indem wir den Zeiger weglassen. Die Verwendung des Schlüsselwortes this ist in keinem Beispielprogramm illustriert, wird aber in einem der größeren Programme dieser Einführung vorkommen.

Du solltest Dir dieses Programm ansehen, bis Du das sichere Gefühl hast, es verstanden zu haben und es dann kompilieren und ausführen, als Vorbereitung auf unser nächstes Beispiel.

Eine verbundene Liste von Objekten

Beispielprogramm: OBJVERB.CPP

Unser nächstes Programm in diesem Kapitel heißt OBJVERB.CPP und ist ein komplettes Beispiel einer verbundenen Liste in objektorientierter Schreibweise.

Dieses Beispielprogramm ist dem letzten sehr ähnlich. In der Tat ist es mit diesem identisch, bis wir zur Funktion main() kommen. Du erinnerst Dich, wir haben im letzten Programm nur über die beiden Methoden ZeigeAufNaechste() und HoleNaechste Zugriff auf die internen Zeiger der Objekte gehabt. Diese Methoden finden sich in den Zeilen 42 bis 52 des Programmes, dem wir uns jetzt widmen wollen. Wir werden sie verwenden, um unsere Liste zu erstellen und sie dann durchzugehen, um die Liste am Bildschirm auszugeben. Schließlich werden wir die komplette Liste löschen, um den Speicher freizugeben.

In den Zeilen 57 bis 59 definieren wir drei Zeiger. Der Zeiger mit dem Namen Start wird immer auf das erste Element der Liste zeigen, Temp hingegen wird durch die Liste wandern, wenn wir sie erstellen. Den Zeiger mit dem Namen BoxZeiger werden wir zum Erzeugen der Objekte verwenden. Die Schleife in den Zeilen 62 bis 75 erzeugt unsere Liste. Zeile 64 erzeugt dynamisch ein neues Objekt der Klasse Box und in Zeile 65 füttern wir dieses Objekt zur Illustration mit sinnlosen Daten. Ist das Objekt, das wir gerade erzeugt haben, das erste in der Liste, lassen wir den Zeiger Start darauf zeigen. Gibt es allerdings schon Elemente in der Liste, lassen wir das letzte Element (repräsentiert durch den Zeiger Temp) auf das neue Zeigen. In jedem Fall weisen wir dem Zeiger Temp das letzte Element in der Liste zu, damit wir noch weitere anfügen können, sollte das gewünscht werden.

In Zeile 78 lassen wir den Zeiger mit dem Namen Temp auf das erste Element zeigen. Wir verwenden diesen Zeiger, um die gesamte Liste zu durchschreiten, wenn er sich selbst durch die Zuweisung in Zeile 82 vorarbeitet. Wenn Temp den Wert NULL hat, den er vom letzten Element in der Liste erhält, haben wir die komplette Liste abgearbeitet.

Schlussendlich löschen wir die gesamte Liste. Wir beginnen beim ersten Element und löschen bei jedem Schleifendurchlauf in den Zeilen 87 bis 92 ein Element.

Einführung in C++ bringt Dich in Partnerschaft mit Amazon.de von Null auf Programmieren in ein paar Klicks.

Zum Beispiel ganz unverbindlich:

Schrödinger programmiert C++: Jetzt mit C++14 und Syntaxhighlighting
Das beste Programmierlernbuch — egal in welcher Sprache? Kann gut sein. Statt trocken ist Dieter Bärs Meisterstück lehrreich, statt mühsam beispielhaft beispielbehaftet, statt Nachschlagewerk (das ist es wirklich nicht) Nur-noch-ein-Bissi-Weitermachbuch und statt unverständlich sinnvoll das Verstehen (statt dem Memorisiern) fördernd erklärend.
›› Mehr C++-Bücher

Ein Studium des Programmes wird zeigen, daß es tatsächlich eine verbundene Liste mit zehn Elementen erzeugt, wobei jedes Element ein Objekt der Klasse Box ist. Die Länge der Liste ist dadurch eingeschränkt, wie viele Elemente wir am Bildschirm ausgeben wollen, sie könnte aber eine Größe von vielen tausend Elementen erreichen, vorausgesetzt, wir haben genug Speicher, um alle diese zu speichern.

Auch hier überprüfen wir die dynamische Speicherverwaltung nicht, wie es in einem korrekt geschriebenen Programm eigentlich geschehen sollte. Kompiliere das Beispielprogramm und führe es aus.

Das Schachteln von Objekten in C++

Beispielprogramm: SCHACHT.CPP

Das Programm SCHACHT.CPP zeigt uns das Schachteln von Klassen, was zu einem Schachteln von Objekten wird. Verschachtelte Objekte können zum Beispiel ganz einfach durch Deinen Computer versinnbildlicht werden. Der Computer selbst besteht aus vielen Teilen, die zusammen, aber doch jeder für sich arbeiten, wie etwa eine Maus, ein Laufwerk oder ein Transformator. Der Computer ist aus diesen so verschiedenen Teilen zusammengesetzt und es ist nur sinnvoll, die Maus getrennt vom Transformator zu betrachten, einfach weil sie so verschieden sind. Eine Klasse für Computer könnte also aus sehr verschiedenen Objekten bestehen, indem die einzelnen Objekte in der Klasse enthalten sind.

Wenn wir aber, zum Beispiel, die Charakteristika von Laufwerken betrachten wollen, werden wir uns zunächst ansehen, was ein Laufwerk generell ausmacht, dann die Eigenheiten einer Festplatte und jene eines CD-ROM Laufwerkes. Das führt zu einer gewissen Vererbung, da viele Daten über die beiden Laufwerke generalisiert und dem Typ "Laufwerk" zugewiesen werden können. Wir werden die Vererbung in den nächsten drei Kapiteln noch eingehend studieren, nun aber wollen wir uns geschachtelten Klassen widmen.

Abb. 6.3

Das Beispielprogramm enthält eine Klasse mit dem Namen Box, die wiederum ein Objekt einer anderen Klasse mit dem Namen PostInfo enthält, das wir in Zeile 17 einfügen. Das stellen wir in Bild 6-3 graphisch dar. Dieses Objekt ist nur innerhalb der Implementation von Box verfügbar, denn dort wurde es ja definiert. Die Funktion main() definiert Objekte der Klasse Box, aber keine der Klasse PostInfo, wir können uns also innerhalb dieser Funktion auf diese Klasse nicht beziehen. In unserem Fall ist die Klasse PostInfo dazu da, von der Klasse Box intern verwendet zu werden, wofür wir in Zeile 22 ein Beispiel geben: Wir senden eine Nachricht an die Methode Etikett.Setze(), um die Variablen zu initialisieren. Zusätzliche Methoden können je nach Bedarf verwendet werden, wir haben nur Beispiele für die Verwendung gegeben.

Einführung in C++ bringt Dich in Partnerschaft mit Amazon.de von Null auf Programmieren in ein paar Klicks.

Zum Beispiel schönes Schachteln:

Der C++-Programmierer: C++ lernen - professionell anwenden - Lösungen nutzen
Eines der jedenfalls besseren Bücher zur Einführung in C++ ist umfassend und verständlich, übersichtlich und gelungen. Halbwegs hübsch anzuschauen ist es auch.
›› Mehr C++-Bücher

Wichtig ist, daß wir im Hauptprogramm kein Objekt der Klasse PostInfo deklarieren, sondern solche bei der Deklaration von Objekten der Klasse Box implizit deklarieren. Natürlich könnten wir auch im Hauptprogramm je nach Bedarf Objekte der Klasse PostInfo deklarieren, wir tun das aber in diesem Beispielprogramm nicht. Um die Sache zu komplettieren, sollte die Klasse Box eine oder mehrere Methoden haben, mit denen die Informationen, die im Objekt der Klasse PostInfo gespeichert sind, verwendet werden können. Schau Dir dieses Programm an, bis Du das neue Konstrukt verstanden hast, kompilieren Sie es und führe es aus. (Kino diesmal?)

Wenn die Klasse und die in sie geschachtelte Klasse Parameter für ihre jeweiligen Konstruktoren benötigen, kann man eine Initialisierungsliste verwenden. Das werden wir später in dieser Einführung diskutieren.

Operatorüberladung

Beispielprogramm: OPUEBER.CPP

Das Programm OPUEBER.CPP enthält Beispiele für das Überladen von Operatoren. Das ermöglicht Dir, eine Klasse von Objekten zu definieren und die Verwendung von normalen Operatoren für diese Klasse neu zu definieren. Das Ergebnis ist, daß die Objekte der Klasse genauso natürlich gehandhabt werden können wie vordefinierte Datentypen. Sie erscheinen als Teil der Sprache und nicht mehr als etwas von Dir Hinzugefügtes.

In diesem Fall überladen wir mit den Deklarationen in den Zeilen 11 bis 13 und den Definitionen in den Zeilen 17 bis 41 die Operatoren + und *. Wir deklarieren die Methoden als Freundfunktionen (friend). Täten wir das nicht, wären die Funktionen Teil eines Objektes und die Nachricht würde an dieses Objekt gesendet werden. Durch die Deklaration als Freundfunktion trennen wir diese vom Objekt und können die Methode quasi "ohne" Objekt aufrufen. Das erlaubt es uns, statt Objekt1.operator+(Objekt2) schlicht und einfach Objekt1 + Objkekt2 zu schreiben. Außerdem wäre ohne das friend Konstrukt ein Überladen mit einer Variable des Typs int als erstem Parameter nicht möglich, da wir an eine solche Variable keine Nachricht senden können, wie etwa int.operator+(Objekt1). Zwei der drei überladenen Operatoren verwenden eine ganze Zahl als ersten Parameter, die Deklaration als Freundfunktion ist also notwendig.

Es gibt kein Limit für die Anzahl an Überladungen pro Parameter. Du kannst jede beliebige Zahl an Überladungen eines Parameters durchführen, solange die Parameter für jede Überladung verschieden sind.

Der Methodenkopf in Zeile 17 illustriert die erste Überladung, die den Operator + betrifft. Wir geben den Rückgabetyp, gefolgt vom Schlüsselwort operator und dem Operator, den wir überladen wollen, an. Die beiden formalen Parameter und deren Typen führen wir in der Klammer an. Die Implementation der Funktion erfolgt in den Zeilen 19 bis 22. Dir ist sicherlich aufgefallen, daß die Implementationen von Freundfunktionen nicht Teil der Klasse sind, deshalb auch der Klassenname nicht angegeben ist. Die Implementation selbst ist biederes Handwerk und sollte Dir auf den ersten Blick einleuchten. Zu Illustrationszwecken vollbringen wir natürlich wieder mathematische Meisterwerke, Du kannst aber auch ganz einfach etwas Nützliches machen.

Die größte Außergewöhnlichkeit passiert in Zeile 57, wo wir die Methode mittels der Operatornotation aufrufen und nicht im normalen Format einer Nachricht, die wir an ein Objekt senden. Da die beiden Variablen Klein und Mittel Objekte der Klasse Box sind, wird das System nach einem Weg suchen, den Operator + mit zwei Objekten der Klasse Box zu verwenden und bei der eben diskutierten Methode operator+() fündig werden. Die Operationen, die wir in der Implementation der Methode durchführen müssen wie gesagt nicht so sinnlos sein, wie das, was wir hier demonstrieren.

Einführung in C++ bringt Dich in Partnerschaft mit Amazon.de von Null auf Programmieren in ein paar Klicks.

Zum Beispiel Operaoren:

Effektives modernes C++
So schwer ist das Programmieren nicht, wie Du hoffentlich auch an und in dieser Einführung siehst. Und auch bessere Programme schreiben ist leichter als man glaubt, wenn man den Meyers intus hat.
›› Mehr C++-Bücher

In Zeile 59 weisen wir das System an, eine Variable vom Typ int zu einem Objekt der Klasse Box zu addieren, das System findet also die zweite Überladung des Operators + in Zeile 26 und führt diese aus. In Zeile 61 schicken wir das System auf die Suche nach einer Methode, die eine Konstante vom Typ int und ein Objekt der Klasse Box mit dem Operator * verbindet und es landet in Zeile 35. Beachte bitte, daß es nicht erlaubt wäre, den Operator * anders herum zu verwenden, also zum Beispiel Grosz * 4, da wir keine Methode definiert haben, die diese Typen in dieser Reihenfolge akzeptiert. Würden wir eine solche Methode definieren könnten wir auch die umgekehrte Schreibweise verwenden, wobei dies zu einem komplett anderen Ergebnis führen kann, da es sich ja um zwei verschiedene Methoden handelt und wir in der Implementation ganz nach unserem Gutdünken panschen können.

Wenn wir Operatorüberladung verwenden, verwenden wir gleichzeitig auch das Überladen von Funktionsnamen, da einige der Funktionsname gleich sind. Wenn wir Operatorüberladung in dieser Form verwenden, sehen unsere Programme so aus, als wäre die Klasse ein natürlicher Teil der Sprache selbst. Deshalb ist C++ eine erweiterbare Sprache und kann an das jeweilige Problem angepaßt werden.

Nachteile des Überladens von Operatoren in C++

Jedes neue Thema, das wir uns ansehen, hat seine Nachteile, vor denen gewarnt werden muß. Das Überladen von Operatoren hat deren anscheinend die meisten, da es so leicht falsch verwendet werden kann und viele Probleme mit sich bringt. Das Überladen von Operatoren ist nur für Klassen verfügbar, Du kannst die Operatoren für die vordefinierten einfachen Typen nicht neu definieren. Das wäre aber ohnedies nicht anzuraten, da Dein Code dann nur sehr schwer lesbar wäre.

Wenn Du den Inkrement- (++) oder den Dekrementoperator (--) überlädst, kann das System nicht feststellen, ob die Aktion vor der Verwendung der Variable im Programm durchgeführt werden soll oder nachher. Welche Methode verwendet wird, hängt allein von der Implementation ab, Du solltest diese Operatoren also in einer Art und Weise verwenden, wo es keine Rolle spielt, wie sie implementiert sind.

Kompiliere dieses Programm und führe es aus, bevor Du zum nächsten Beispielprogramm weitergehst.

Funktionsüberladung in einer Klasse

Beispielprogramm: FUNUEBER.CPP

Das Programm FUNUEBER.CPP gibt uns ein Beispiel für das Überladen von Funktionsnamen in einer Klasse. In dieser Klasse überladen wir den Konstruktor und eine der Methoden, um zu demonstrieren, was gemacht werden kann.

Diese Datei zeigt einige der Verwendungsmöglichkeiten von überladenen Funktionsnamen und ein paar Regeln für ihre Anwendung. Du wirst Dich erinnern, daß die Auswahl der Funktion allein nach der Anzahl und dem Typ der formalen Parameter erfolgt. Der Typ des Rückgabewertes hat darauf keinen Einfluß.

In diesem Fall haben wir drei Konstruktoren. Welcher der Konstruktoren aufgerufen wird, entscheidet sich anhand der Anzahl und der Typen der Parameter in der Definition. In Zeile 78 des Hauptprogrammes deklarieren wir die drei Objekte, jedes mit einer anderen Anzahl an Parametern und wenn wir uns das Ergebnis ansehen, können wir leicht erkennen, dass der jeweils richtige Konstruktor aufgerufen wurde.

Einführung in C++ bringt Dich in Partnerschaft mit Amazon.de von Null auf Programmieren in ein paar Klicks.

Zum Beispiel gar nicht überladen:

Clean Code - Refactoring, Patterns, Testen und Techniken für sauberen Code: Deutsche Ausgabe
Auch, wenn man nicht alles hier gut findet, macht Martins "Clean Code" einen unvermittelt (und unverhinderbar) zur besseren Programmiererin. Viele, viele Beispiele, ergo sehr, sehr lehrreich.
›› Mehr Softwareentwicklung-Bücher

Bei den anderen überladenen Methoden wird die passende Methode genauso festgestellt. Eine der Nachrichten beinhaltet eine Variable vom Typ int, eine andere eine Variable vom Typ float, das System findet aber die passende Methode. Du kannst eine Methode so oft überladen, wie Du willst, solange die Parameter eindeutig sind.

Vielleicht denkst Du nun, daß das ganze nicht viel Sinn macht und bist geneigt, es als Spielerei abzutun, das Überladen ist aber sehr wichtig. Die gesamte Einführung hindurch haben wir einen überladenen Operator verwendet, ohne daß Du irgendetwas Außergewöhnliches daran gefunden hättest. Es handelt sich um den Operator <<, der Teil der Klasse cout ist. Dieser Operator ist überladen, da die Form der Ausgabe von der Eingabevariable abhängt. Viele Programmiersprachen haben überladene Ausgabefunktionen, damit Du alle möglichen Daten mit ein und demselben Funktionsname ausgeben kannst.

Kompiliere das Programm und führe es aus.

Getrennte Kompilation in C++

Die getrennte Kompilation von einzelnen Dateien folgt in C++ genau denselben Regeln wie in ANSI-C. Getrennt kompilierte Dateien können zusammen-"gelinkt" werden. Da aber Klassen dazu verwendet werden, um Objekte zu definieren, ist die Natur der getrennten Kompilation in C++ von jener in ANSI-C verschieden. Die Klassen werden nämlich nicht als externe Variablen angesehen, sondern als interne Klassen. Das läßt das Programm anders als ein reines ANSI-C Programm aussehen.

Einige Methoden kommen von selbst

Beispielprogramm: AUTOMETH.CPP

Selbst wenn Du keine Konstruktoren oder überladene Operatoren schreibst, definiert der Compiler einige automatisch. Wirf einen Blick auf die Datei AUTOMETH.CPP, die einige dieser Methoden illustriert und zeigt, warum Du manchmal die automatisch bereitgestellten nicht verwenden kannst, sondern selbst Methoden schreiben mußt, die deren Arbeit übernehmen.

Bevor wir uns dem Programm selbst widmen, wollen wir einige der Regeln angeben, die Autoren von Compilern berücksichtigen müssen. Wir werden sie zuerst überblicksmäßig anführen, um dann ein wenig darauf einzugehen.

  1. Wenn für eine Klasse kein Konstruktor existiert, erzeugt der Compiler automatisch einen Konstruktor und einen Kopierkonstruktor. Beide werden wir definieren.
  2. Ist ein Konstruktor vorhanden, erzeugt der Compiler keinen.
  3. Wenn für eine Klasse kein Kopierkonstruktor existiert, erzeugt der Compiler einen, nicht jedoch, wenn der Autor der Klasse einen Kopierkonstruktor geschrieben hat.
  4. Ist ein Zuweisungsoperator vorhanden, erzeugt der Compiler nicht automatisch einen, andernfalls schon.

Für jede Klasse, die wir einem C++ Programm deklarieren und verwenden, muß es möglich sein, ein Objekt zu "konstruieren", da der Compiler definitionsgemäß einen Konstruktor aufrufen muß, wenn wir ein Objekt definieren. Wenn wir selbst keinen Konstruktor schreiben, erzeugt der Compiler selbst einen, den er beim Konstruieren von Objekten aufrufen kann. Das ist der Standardkonstruktor, den wir ohne es zu wissen, schon in vielen unserer Beispielprogramme verwendet haben. Der Standardkonstruktor initialisiert keine Elementvariablen, setzt aber alle internen Referenzen und ruft den Konstruktor (oder die Konstruktoren) der Basisklasse auf, falls solche existieren. Wir haben die Vererbung noch nicht studiert, werden uns diesem Kapitel aber im nächsten Abschnitt unserer Einführung widmen, dann wirst Du auch über Basisklassen Bescheid wissen. In Zeile 10 deklarieren wir einen Konstruktor, der aufgerufen wird, wenn wir ein Objekt ohne Parameter definieren. In diesem Fall ist der Konstruktor notwendig, da wir eine interne Zeichenkette haben, für die dynamisch Speicher beschafft und die mit einer leeren Zeichenkette initialisiert werden muß. Denk kurz darüber nach, und Du wirst sehen, daß dieser unser Konstruktor viel besser ist als der Standardkonstruktor, der einen initialisierten Zeiger zurücklassen würde.

Dieser Konstruktor wird in Zeile 77 des Beispielprogrammes verwendet.

Der Kopierkonstruktor

Wenn Du für eine Klasse selbst keinen Kopierkonstruktor definieren, wird dieser vo Compiler automatisch erzeugt. Er wird dazu verwendet, um bei der Erzeugung eines neuen Objektes den Inhalt eines anderen Objektes in das neue zu kopieren. Wenn der Compiler den Kopierkonstruktor für Dich definiert, kopiert dieser einfach den Inhalt Byte für Byte, was möglicherweise nicht genau das ist, was Du willst. Für einfache Klassen ohne Zeiger reicht der Standard-Kopierkonstruktor aus, aber in diesem Beispielprogramm haben wir einen Zeiger auf ein Element der Klasse und eine Kopie Byte für Byte würde auch diesen Zeiger einfach kopieren. Das würde dazu führen, daß beide Objekte auf dieselbe Adresse im Speicher und damit dieselbe Variable zeigen. Für unsere Klasse deklarieren wir den Kopierkonstruktor in der Zeile 13, die Implementation erfolgt in den Zeilen 33 bis 38. Wenn Du Dir die Implementation etwas genauer ansiehst, wirst Du feststellen, daß das neue Objekt in der Tat eine Kopie des alten ist, aber mit einer eigenen Zeichenkette. Da beide, der Konstruktor und der Kopierkonstruktor, dynamisch Speicherplatz beschaffen, müssen wir sicherstellen, daß dieser Speicher auch wieder freigegeben wird, wenn die Objekt zu existieren aufhören. Deshalb ist es notwendig, eine Destruktor bereitzustellen, dessen Implementation in den Zeilen 49 bis 52 dieses Beispielprogrammes zu finden ist. Den Kopierkonstruktor verwenden wir in Zeile 83.

Der C++ Zuweisungsoperator

Es ist zwar nicht gleich ersichtlich, aber auch ein Zuweisungsoperator ist für dieses Beispielprogramm notwendig, da der Standardzuweisungsoperator einfach eine Kopie des Speicherinhaltes herstellt. Das würde in demselben Problem resultieren wie beim Kopierkonstruktor. Wir deklarieren den Zuweisungsoperator in Zeile 16 und definieren ihn in den Zeilen 40 bis 49. Wir löschen zuerst die alte Zeichenkette des existierenden Objektes, dann stellen wir den Speicher für den neuen Text bereit und kopieren ihn vom Quellobjekt in das neue Objekt. Den Zuweisungsoperator verwenden wir in der Zeile 90.

Es ist ziemlich offensichtlich, dass die obigen drei Methoden zusätzlich zu einem Destruktor bereitgestellt werden sollten, wenn eine Klasse dynamische Speicherverwaltung beinhaltet. Wenn Du einen der vier vergißt, kann das Programm ein eigenartiges Verhalten an den Tag legen. Kompiliere dieses Programm und führe es aus.

Ein praktisches Beispiel

Beispielprogramm: PHRASE.H

Die Verwendung des Schlüsselwortes inline kann einige Verwirrung stiften, wenn Du nicht weißt, wie der Compiler die Definition des Codes bei der Implementation verwendet. Betrachte die header-Datei PHRASE.H, die einige inline-Methoden enthält. Wir wollen damit einen sauberen Weg aufzeigen, wie inline-Methoden deklariert werden können, mit denen der Compiler auch etwas anfängt.

Jede Implementation, die diese Klasse verwendet, muß Zugriff auf die Implementation der inline-Methoden haben, um den Code für die Methoden einsetzen zu können. Ein Weg, dies zu erreichen ist, eine eigenen Datei (Erweiterung INL) mit allen inline-Methoden zu erstellen und diese Datei dann am Ende der header-Datei einzufügen, wie wir es hier in Zeile 17 tun. Dadurch steht dem Compiler jederzeit der gesamte Code zur Verfügung.

Beispielprogramm: PHRASE.INL

Die Datei PHRASE.INL enthält alle die inline-Methoden der Klasse.

Beispielprogramm: PHRASE.CPP

Der einzige Grund, warum es diese Datei überhaupt gibt, ist, die statische Variable GanzePhrase zu definieren. Da es sich um eine Definition handelt und deshalt Speicher belegt wird, können wir sie nicht in eine header-Datei schreiben. Täten wir das doch, hätte es den Anschein, als funktionierte alles prächtig, da die header-Datei nur einmal verwendet wird. Das Verwenden einer schlechten Programmiertechnik wie dieser würde aber früher oder später zu Problemen führen. Aus Demonstrationsgründen haben wir alle Methoden inline deklariert, deshalb gibt es in dieser Datei keine Definitionen von Methoden.

Beispielprogramm: VERPHRAS.CPP

Die Datei VERPHRAS.CPP verwendet die Klasse Phrase, die wir in den letzten beiden Beispielprogrammen definiert haben. Es ist klar zu sehen, daß diese Klasse sich in nichts von all den anderen, die wir schon betrachtet haben, unterscheidet. Sie zeigt nur, wie inline-Code einfach und effizient gehandhabt werden kann.

Ein weiteres praktisches Beispiel für Klassen in C++

Auch hier wollen wir uns eine praktische Klasse ansehen, die in einem Programm verwendet werden kann, aber doch einfach genug ist, damit Du sie komplett verstehen kannst.

Beispielprogramm: ZEIT.H

Im letzten Kapitel haben wir uns die Klasse Datum angesehen, in diesem wollen wir uns der Klasse Zeit widmen. Du solltest mit dem Studium der Datei ZEIT.H beginnen, die der header-Datei der Datum Klasse sehr ähnlich sieht. Der einzige große Unterschied sind die überladenen Konstruktoren und Methoden. Es handelt sich hier um ein sehr praktisches Beispiel, das recht gut illustriert, daß viele Überladungen des Konstruktors möglich sind.

Beispielprogramm: ZEIT.CPP

Die Implementation der Klasse Zeit erfolgt in der Datei ZEIT.CPP. Auch dieser Code ist sehr einfach und Du solltest keinerlei Schwierigkeit haben, ihn vollkommen zu verstehen. Drei der vier überladenen Funktionen rufen die vierte auf, damit der Code dieser Methode nicht vier Mal wiederholt werden muss. Das ist relativ gute Programmierpraxis und zeigt, dass innerhalb der Implementation andere Elementfunktionen aufgerufen werden können.

Wie wir schon einmal erwähnt haben, verwendet der Code Betriebssystemaufrufe und ist damit nicht ohne weiteres portierbar. Du mußt den Code dann adaptieren oder einfach Standardwerte zuweisen.

Einführung in C++ bringt Dich in Partnerschaft mit Amazon.de von Null auf Programmieren in ein paar Klicks.

Zum Beispiel Beispielhaftes:

Design Patterns: Entwurfsmuster als Elemente wiederverwendbarer objektorientierter Software (mitp Professional)
Programmieren ist Problemlösen. Dieser Klassiker hilft dabei und hat Antworten auf die Fragen, die mit "Wie mache ich...?" beginnen.
›› Mehr Softwareentwicklung-Bücher

Beispielprogramm: VERZEIT.CPP

Das Beispielprogramm VERZEIT.CPP verwendet die Klasse Zeit in einer sehr einfachen Art und Weise. Du solltest es sofort verstehen. Es ist sicherlich nützlich, wenn Du die beiden praktischeren Beispiele am Ende des letzten und dieses Kapitels verstanden hast. Wie schon erwähnt werden wir nämlich die Klassen Zeit und Datum als Basis der einfachen und der vielfachen Vererbung benutzen, wenn wir diese in den nächsten drei Kapiteln untersuchen.

Was sollte der nächste Schritt beim C++ Programmieren sein?

Jetzt weißt Du schon genug über C++, um sinnvolle Programme zu schreiben und es hilft Dir sicherlich sehr, wenn Du diese Einführung ein wenig beiseite legst und beginnst, das anzuwenden, was Du gelernt hast. Da C++ ja eine Erweiterung von ANSI-C ist, können die Schritte beim Erlernen etwas kleiner sein, als wenn man eine komplett neue Sprache erlernt. Du hast mittlerweile genug gelernt, um Dich mit dem Beispielprogramm des Kapitels 12, dem Abenteuerspiel, auseinanderzusetzen. Damit solltest Du jetzt beginnen.

Das größte Problem ist es, objektorientiert zu denken. Das ist gar nicht so einfach, wenn man einige Zeit in prozeduralen Sprachen programmiert hat. Aber auch das kann man (nur) durch Übung lernen, Du solltest also versuchen, in Klassen und Objekten zu denken. Dein erstes Projekt sollte nur einige Objekte umfassen, den Rest kannst Du ruhig prozedural schreiben. Mit der Zeit und der Erfahrung wirst Du immer mehr Code mit Klassen und Objekten schreiben, vollenden wirst Du aber jedes Projekt mit prozeduralen Programmiertechniken.

Wenn Du einige Zeit mit den Techniken, die wir bis hierher in dieser Einführung besprochen haben, programmiert hast, kannst Du zum nächsten Kapitel weitergehen. Dieses Kapitel wird sich mit Vererbung und virtuellen Funktionen beschäftigen.

Programmieraufgaben

  1. Mach aus Klein und Mittel in OBJDYNAM.CPP Zeiger. Beschaffe Speicherplatz für sie, bevor Du sie verwendest.
  2. Ändere in OBJVERB.CPP die Schleife in Zeile 62 so, daß sie 1000 Elemente speichert. Es ist wahrscheinlich klug, die Ausgabe in Zeile 81 auszukommentieren. Möglicherweise erzeugst Du mit so großen Zahlen einen Speicherüberlauf, was Du an falschen Antworten erkennst, wenn Du eine Nachricht an HoleFlaeche() sendest. Das hängt von Deinem Compiler ab.
  3. Schreibe ein Programm, das sowohl die Zeit als auch die Datum Klasse sinnvoll verwendet. Diese beiden Klassen kannst Du in allen zukünftigen C++ Programmen verwenden, um Zeit und Datum der Ausführung festzuhalten.

(weiter »)

Einführung in C++ bringt Dich in Partnerschaft mit Amazon.de von Null auf Programmieren in ein paar Klicks.

Zum Beispiel Objektdaten schützen:

Objektorientierte Programmierung: Das umfassende Handbuch. Lernen Sie die Prinzipien guter Objektorientierung.
Ungefähr alles nicht nur, das man wissen muss, sondern auch, das man wissen kann, in einem Buch. Dabei ist "Objektorientierte Programmierung" nicht unpraktisch und langweilig, nein: voll mit Beispielen und vor allem verständlichen Erklärungen, macht es einen interessiert — und mit brauchbarer objektorientierung zur besseren Programmiererin.
›› Mehr Softwareentwicklung-Bücher

[ Es ]