Einführung in C++ Kapitel 5 — Zugriffsschutz

Wie wir schon im ersten Kapitel festgestellt haben, erscheint einer Programmiererin, die viel Erfahrung in der prozeduralen Programmierung hat, des objektorientierte Programmieren reichlich unnatürlich. Mit diesem Kapitel beginnen wir unsere Definition objektorientierten Programmierens und widmen uns dem Zugriffsschtz, der dem Motto "divide et impera" (Teile und herrsche) folgt. Wie wir auch schon festgestellt haben, bringt das objektorientierte Programmieren natürlich wieder eine Reihe neuer Begriffe und Namen aufs Tableau. Laß' Dich von der neuen Terminologie aber nicht abschrecken, es wird alles halb so schlimm sein, wenn wir uns einen Begriff nach dem anderen in einer sinnvollen Reihenfolge vornehmen.

Der Zugriffsschutz ist eigentlich das Erzeugen von Objekten, dem wir uns während des gesamten Kapitels widmen werden. Ein Objekt mit Zugriffsschutz wird oft auch ein abstrakter Datentyp genannt und um diesen dreht sich das gesamte objektorientierte Programmieren. Ohne Zugriffsschutz, der nur unter Verwendung einer oder mehrerer Klassen möglich ist, gibt es kein objektorientiertes Programmieren. Natürlich hat die Objektorientierung noch andere Aspekte, der Zugriffsschutz ist aber der Kern der Sache.

Wozu das alles?

Wir brauchen einen Zugriffsschutz, weil wir Menschen sind, und weil Menschen nun einmal Fehler machen. Wenn wir Quellcode richtig vor (falschem) Zugriff schützen, bauen wir eine Mauer rundherum, die den Code vor zufälligen Änderungen durch all die dummen Fehler, die wir so gerne machen, schützt. Außerdem können wir Fehler auf ein relativ kleines Gebiet zurückführen und sie so schneller finden und beheben. Einiges mehr noch wird über die Vorteile des Zugriffsschutzes zu sagen sein, wenn wir in diesem Kapitel voranschreiten.

Kein Zugriffsschutz

Beispielprogramm: OFFEN.CPP

Das Programm mit dem Namen OFFEN.CPP ist ein wirklich dummes Programm, es macht nämlich so gut wie gar nichts. Es soll aber unser Ausgangspunkt für die Diskussion des Zugriffsschutzes sein, auch als das Vorenthalten von Information bekannt. Der Zugriffsschutz ist ein wichtiger Teil des objektorientierten Programmierens und Du solltest am Ende dieses Kapitels mit Fug und Recht von sich behaupten können, ihn zu verstehen.

In den Zeilen 4 bis 7 definieren wir eine sehr einfache Struktur, die aus einer einzigen Variable vom Typ int besteht. Das ist nicht unbedingt sinnvoll, soll aber das Problem illustrieren, das wir in diesem Kapitel lösen wollen. In Zeile 11 deklarieren wir drei Variablen, die alle aus einer einzelnen Variable vom Typ int bestehen und alle drei überall innerhalb der Funktion main() verfügbar sind. Wir können jeder Variable Werte zuweisen, sie inkrementieren, lesen, ändern oder was auch immer mit ihr anstellen. Einige der möglichen Operationen werden in den Zeilen 14 bis 22 gezeigt und sollten mit ein wenig Erfahrung in C klar sein.

Abb. 5-1Eine einzelne lokale Variable mit dem Namen Schweinchen deklarieren und verwenden wir mehr oder weniger parallel, um zu zeigen, daß es sich bei diesem Code um nichts Außergewöhnliches handelt. Bild 5-1 stellt den Speicherzustand nach der Abarbeitung von Zeile 17 bildhaft dar.

Schau Die dieses Beispielprogramm genau an, es ist nämlich die Basis unseres Studiums des Zugriffsschutzes. Kompiliere das Programm und führe es aus, dann gehen wir weiter zu unserem nächsten Programm, dem ersten mit richtigem Zugriffsschutz.

Zugriffsschutz

Beispielprogramm: KLAS.CPP

Das Programm KLAS.CPP ist unser erstes Beispiel für ein Programm mit ein wenig Zugriffsschutz. Das Programm ist identisch mit dem letzten abgesehen davon, daß es einige Operationen etwas anders durchführt. Wir werden uns die Unterschiede der Reihe nach ansehen und erklären, was passiert. Bedenke, daß es sich hier um ein wirklich triviales Beispiel handelt, wo die Sicherheitsmaßnahmen nicht von Nöten sind, sondern nur dazu dienen sollen, ihre Verwendung (in einem komplizierteren Programm) zu illustrieren.

Der erste Unterschied besteht darin, daß wir anstatt einer Struktur in Zeile 4 eine Klasse haben. Der einzige Unterschied zwischen Struktur und Klasse ist der, daß die Klasse mit einer privaten Sektion beginnt, die Struktur mit einer öffentlichen. Das Schlüsselwort class wird verwendet, um eine Klasse zu deklarieren, wie hier gezeigt.

Die Klasse mit dem Namen Daten beseht aus einer einzelnen Variable mit dem Namen DatenSpeicher und zwei Funktionen, eine mit dem Namen SetzeWert(), die andere mit dem Namen HoleWert(). Eine etwas komplettere Definition einer Klasse wäre etwa die einer Gruppe von Variablen und einer oder mehrerer Funktionen, die mit diesen Variablen arbeiten. Wir werden all das sehr bald in eine sinnvolle und nützliche Ordnung bringen.

Was sind private Elemente?

Alle Daten am Anfang einer Klasse sind automatisch private Daten. Deshalb kann auf Daten, die am Beginn einer Klasse stehen, von außen nicht zugegriffen werden, sie sind sozusagen versteckt. Darum kann auf die Variable mit dem Namen DatenSpeicher, die ein Teil des in Zeile 24 definierten Objektes (was genau ein Objekt ist werden wir später definieren) mit dem Namen Hund1 ist, nirgends innerhalb der Funktion main() zugegriffen werden. Es ist, als hätten wir um die Variablen eine Mauer errichtet, um sie vor äußeren Programmeinflüssen zu schützen. Es erscheint eigentlich dumm, in der Funktion main() eine Variable zu definieren, die wir gar nicht nutzen können, genau das haben wir aber soeben getan.

Abb. 5-2Bild 5-2 illustriert die Klasse mit ihrer Mauer rund um die Daten, um diese zu schützen. Dir sind sicherlich die kleinen Löcher aufgefallen, die wir offen gelassen haben, um der Benutzerin den Zugriff auf die Funktionen SetzeWert() und HoleWert() zu ermöglichen. Diese Löcher haben wir geöffnet, indem wir die Funktionen als öffentliche Elemente der Klasse definiert haben.

Was sind öffentliche Elemente?

In Zeile 7 führen wir ein neues Schlüsselwort ein: public. Dieses Schlüsselwort sagt aus, daß alles darauf folgende auch außerhalb der Klasse verfügbar ist. Da wir unsere zwei Funktionen nach dem Schlüsselwort public definiert haben, sind sie öffentliche Funktionen und können von jeder Funktion aus aufgerufen werden, die im Gültigkeitsbereich dieses Objektes liegt. Das öffnet zwei Löcher in der Mauer, die wir um unsere Daten gebaut haben, um sie zu schützen. Denke aber immer daran, daß die private Variable für die aufrufende Funktion nicht verfügbar ist. Deshalb können wir die Variable nur verwenden, indem wir eine der zwei Funktionen aufrufen, die wir als öffentliche Funktionen definiert haben. Diese Funktionen werden Elementfunktionen genannt, da sie Elemente der Klasse sind.

Nachdem wir zwei Funktionen deklariert haben, müssen wir sie nun auch definieren und angeben, was sie eigentlich tun sollen. In den Zeilen 12 bis 20 tun wir das ganz normal, mit dem einzigen Unterschied, daß den Funktionsnamen der Klassenname, getrennt durch einen zweifachen Doppelpunkt, vorausgeht. Die beiden Funktionsdefinitionen werden die Implementation der Funktionen genannt. Wir müssen den Klassennamen angeben, da es uns freisteht, denselben Funktionsnamen innerhalb mehrerer Klassen zu verwenden und der Compiler wissen muß, welche Funktionsimplementation welcher Klasse zuzuordnen ist.

Abb. 5-3Eine der wichtigsten Erkenntnisse, die wir hier gewinnen sollen, ist jene, daß all die privaten Daten der Klasse innerhalb der Implementationen der Elementfunktionen der Klasse ganz normal für Änderungen zur Verfügung stehen. Innerhalb der Funktionsimplementationen, die ja zur Klasse gehören, kannst Du mit den privaten Daten der Klasse alles anstellen, private Daten anderer Klassen sind allerdings nicht verfügbar. Das ist auch der Grund, warum wir dem Funktionsnamen den Klassennamen voranstellen müssen, wenn wir sie definieren. Bild 5-3 zeigt den Speicher nach dem Abarbeiten der Zeile 30.

Es soll nicht unerwähnt bleiben, daß es natürlich erlaubt ist, private Variablen und Funktionen zu deklarieren und dann im öffentlichen Teil zusätzliche Variablen und Funktionen. In den meisten Fällen werden die Variablen ausschließlich im privaten Teil deklariert und die Funktionen nur im öffentlichen. Manchmal wird man aber Variablen oder Funktionen auch im jeweils anderen Teil deklarieren. Das führt oft zu sehr praktischen Lösungen für spezielle Probleme, im Allgemeinen werden die Elemente aber nur in den erwähnten Teilen verwendet.

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

Zum Beispiel Elementares:

C++. Der Einstieg
Ein bewährtes Buch auf halben Wegs aktuellem Stand: Arnold Willemers "C++. Der Einstieg" eignet sich tatsächlich zum Einstieg ins Programmieren mit C++ und erklärt klar strukturiert mit, ganz wichtig, allerhand Beispielen alles Wichtige.
›› Mehr C++-Bücher

In C++ gibt es vier verschiedene Gültigkeitsbereiche für Variablen: global, lokal, in einer Datei und in einer Klasse. Globale Variablen sind überall in der Datei, in der sie definiert werden, und auch in anderen Dateien verfügbar. Lokale Variablen sind auf eine einzelne Funktion beschränkt. Dateien, die außerhalb jedweder Funktion definiert werden, sind im auf ihre Definition folgenden Rest der Datei verfügbar. Eine Variable mit dem Gültigkeitsbereich einer Klasse schließlich ist überall innerhalb des Gültigkeitsbereiches der Klasse, der die Implementationen mit einschließt, verfügbar und nirgends sonst. Die Variable DatenSpeicher ist eine solche Variable.

Du wirst jetzt einigermaßen verwirrt sein, da wir eine Reihe von Regeln aufgestellt haben, ohne je Gründe für diese anzuführen. Lies weiter und Du wirst sehen, daß es doch recht vernünftige und brauchbare Gründe für all das gibt.

Mehr neue Terminologie

Wann immer Menschen etwas Neues entwickeln, sind sie der festen Überzeugung, daß das Neue durch einen neuen Namen auch würdig gefeiert werden muß. Da bildet die Objektorientierung keine Ausnahme, also müssen wir uns an einige neue Bezeichnungen für gute alte Bekannte gewöhnen, wenn wir lernen, sie effektiv einzusetzen. Um Dir dabei behilflich zu sein, werden wir hier einige dieser Begriffe aufzählen und beginnen hiermit, sie auch im Text zu benutzen, damit Du Dich an sie gewöhnen kannst. Du wirst möglicherweise nicht alle gleich verstehen, es ist aber sicherlich sinnvoll, sie möglichst früh einzuführen.

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

Zum Beispiel, ach ja, Terminologie:

Basiswissen für Softwareprojektmanager im klassischen und agilen Umfeld: Aus- und Weiterbildung zum ASQF® Certified Professional for Project Management (CPPM) (iSQI-Reihe)
Was gibt es schöneres als ASQF, CPPM und CMMI? Ja, wissen was all das bedeutet und wie es helfen kann, das Wort "Scheitern" aus dem Softwareprojektwortschatz zu verbannen.
›› Mehr Projektmanagement-Bücher

Mit all dieser neuen Terminologie werden wir nun unser Studium des Programmes KLAS.CPP fortsetzen und zeigen, wie die Klasse verwendet wird. Wir halten einmal fest, daß wir eine Klasse mit einer Variablen und zwei Methoden haben. Die Methoden operieren mit den Variablen, wenn eine Nachricht sie anweist, das zu tun. In dieser Einführung werden wir die Bezeichnungen Objekt und Variable austauschbar verwenden, da beide ganz gut wiedergeben, was ein Objekt wirklich ist.

Das folgende ist nur ein kleiner Punkt, kann daher aber auch leicht übersehen werden. Die Zeilen 8 und 9 enthalten die Prototypen für unsere zwei Methoden und sind damit unser erstes Beispiel für eine Prototypen innerhalb einer Klasse. Aus diesem Grund haben wir uns den Prototypen im letzten Kapitel so eingehend gewidmet. Was sagt Zeile 8 aus? Die Methode mit dem Namen SetzeWert() verlangt einen Parameter vom Typ int und gibt nichts zurück, der Rückgabetyp ist also void. Die Methode mit dem Namen HoleWert() allerdings hat keine Eingabeparameter, gibt aber einen Wert vom Typ int zurück an den Aufrufenden.

Das Senden einer Nachricht

Nach all den Definitionen in den Zeilen 1 bis 20 kommen wir dann endlich zum Programm, wo die Klasse auch wirklich zum Einsatz kommt. In Zeile 24 definieren wir drei Objekte der Klasse Daten und nennen sie Hund1, Hund2 und Hund3. In dieser Zeile verwenden wir das Schlüsselwort class nicht nocheinmal, einfach weil es nicht notwendig ist. Jedes der Objekte beinhaltet eine Information, auf die wir mittels der Methoden SetzeWert() und HoleWert() zugreifen können. Wir können diese Information aber nicht direkt setzen oder ihren Wert lesen, da diese Information innerhalb unserer Mauer rund um die Klasse versteckt ist. In Zeile 27 senden wir an das Objekt mit dem Namen Hund1 eine Nachricht, die es anweist, den Wert der internen Variable auf 12 zu setzen. Obwohl dies wie ein Funktionsaufruf aussieht, wollen wir es richtiger das Senden einer Nachricht an das Objekt nennen. Du erinnerst Dich, daß das Objekt mit dem Namen Hund1 eine zu ihm gehörige Methode mit dem Namen SetzeWert() hat, die den Wert der internen Variable auf den Parameter der Methode setzt. Sicherlich ist Dir aufgefallen, daß die Form sehr dem Zugriff auf ein Element einer Struktur ähnelt. Du gibst den Namen des Objektes an, gefolgt von einem Punkt und dann dem Namen der Methode. Genauso senden wir auch an die anderen zwei Objekte, Hund2 und Hund3 Nachrichten, ihre Werte auf die jeweils angegebenen Parameter zu setzen.

Die Zeilen 32 und 33 haben wir auskommentiert, da diese Aktionen nicht erlaubt sind. Die Variable mit dem Namen DatenSpeicher ist privat und damit außerhalb des Objektes selbst nicht verfügbar. Es sollte klar sein, daß die Daten, die das Objekt Hund1 beinhaltet, in den Methoden von Hund2 und Hund3 nicht verfügbar sind, da es sich um verschiedene Objekte handelt. All diese Regeln sollen Dir dabei helfen, schneller besseren Code zu schreiben und wir werden bald sehen wie sie das tun.

Die andere für jedes Objekt definierte Methode kommt in den Zeilen 35 bis 37 zum Einsatz, um zu illustrieren, wie sie verwendet wird. Es wird jeweils eine weitere Nachricht an das jeweilige Objekt gesendet und der zurückgegebene Wert mittels der Strömebibliothek am Bildschirm ausgegeben.

Eine normale Variable verwenden

Wir deklarieren eine andere Variable mit dem Namen Schweinchen und verwenden sie in diesem Beispielprogramm, um zu zeigen, daß eine normale Variable mit den Objekten gemischt und ganz normal verwendet werden kann. Die Verwendung dieser Variable sollte Dir keine allzu großen Rätsel aufgeben. Wenn Du dieses Programm also verstanden hast, kompiliere es und laß es laufen. Dann entferne die Kommentarzeichen aus den Zeilen 32 und 33 und achte darauf, welche Fehlermeldung der Compiler ausgibt.

Ein Programm mit Problemen

Beispielprogramm: MASTOFFN.CPP

Das Programm MASTOFFN.CPP ist ein Beispiel, das einige ernsthafte Probleme aufzeigt, die wir dann im nächsten Beispielprogramm mithilfe des Zugriffsschutzes überwinden werden.

Wir deklarieren zwei Strukturen, eine für ein Rechteck, die andere für einen Masten. Die einzelnen Datenfelder sollten klar sein, mit Ausnahme der Tiefe des Fahnenmasten, wobei es sich darum handelt, wie tief er im Boden verankert ist. Die gesamte Länge des Fahnenmasten ergibt sich demnach aus der Laenge plus der Tiefe.

Abb. 5-4Bild 5-4 zeigt den Speicher für dieses Programm nach dem Abarbeiten der Zeile 34. Mit Deiner Erfahrung im Programmieren in ANSI-C sollten beim Verständnis dieses Programmes keinerlei Probleme auftreten. Einzig das Ergebnis der Zeile 40, wo wir die Hoehe des Quadrat mit der Breite der Box multiplizieren, wird Dich etwas verwundern. Das ist in ANSI-C genauso wie in C++ erlaubt, hat aber keine "weltliche" Bedeutung und keinen Sinn, da die Daten von zwei verschiedenen Elementen stammen. So ist das Ergebnis von Zeile 42 noch sinnloser, denn das Produkt der Hoehe des Quadrat und der Tiefe des Fahnenmast hat absolut keine Bedeutung in irgendeinem denkbaren physikalischen System. In einem Programm, das so einfach ist wie dieses, ist der Fehler offensichtlich, in einem größeren Programm schleichen sich solche Fehler aber sehr leicht ein und sind oft nur sehr mühsam wieder zu finden.

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

Zum Beispiel Problemvermeidung:

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

Wäre es nicht schön, wenn wir einen Weg fänden, solche dummen Fehler in großen Industrieprogrammen zu vermeiden? Hätten wir ein gutes Programm, das genau definiert, welche Dinge wir mit einem Rechteck anstellen können und ein zweites Programm, das genau definiert, was wir mit einem Mast tun können und wären die Daten vor äußerem Zugriff geschützt, dann könnten wir solche Dinge verhindern. Wenn diese Elemente miteinander arbeiten sollen, können wir sie nicht in einzelnen Programmen verwirklichen, wohl aber können wir sie auf Klassen aufteilen, um unser Ziel zu erreichen.

Es wird Dich nicht überraschen, daß unser nächstes Programm genau das für uns tun wird und noch dazu in einer eleganten Art und Weise. Bevor wir aber weitergehen, solltest Du dieses Programm kompilieren und laufen lassen und Dich an den abstrusen Ergebnissen erfreuen.

Objekte schützen Daten

Beispielprogramm: KLASMAST.CPP

Das Beispielprogramm KLASMAST.CPP illustriert den Schutz von Daten in einem sehr einfachen Programm.

In diesem Programm haben wir aus dem Rechteck eine Klasse mit denselben zwei Variablen, die nun privat sind, und zwei Methoden, die mit diesen Variablen arbeiten können, gemacht. Eine Methode dient dazu, die Werte der erzeugten Objekte zu initialisieren und die andere Methode gibt den Flächeninhalt des Objektes zurück. Die Methoden definieren wir in den Zeilen 13 bis 22 so wie wir es oben in diesem Kapitel beschrieben haben. Der Mast ist weiterhin eine Struktur, um zu zeigen, daß die beiden parallel verwendet werden können und C++ tatsächlich eine Erweiterung von ANSI-C ist.

Abb. 5-5

In Zeile 35 definieren wir zwei Objekte, die wir wieder Box und Quadrat nennen, diesmal können wir ihren Elementen allerdings nicht direkt Werte zuweisen, da es sich um private Elemente der Klasse handelt. Bild 5-5 zeigt die beiden Objekte, die im aufrufenden Programm verfügbar sind. Deshalb haben wir die Zeilen 38 bis 40 auskommentiert und senden anstatt dessen in den Zeilen 42 und 43 Nachrichten an die Objekte, die sie anweisen, sich selbst mit den als Parametern angegebenen Werten zu initialisieren. Der Fahnenmast wird in derselben Weise initialisiert wie im vorigen Programm. Die Verwendung der Klasse bewahrt uns vor den unsinnigen Berechnungen, die wir im letzten Beispielprogramm angestellt haben, da wir die Fläche eines Objektes nur mit den im Objekt selbst gespeicherten Daten berechnen können. Nun verwenden wir den Compiler, um die sinnlose Rechnerei zu verhindern. Das Endergebnis ist, daß die sinnlosen Berechnungen des letzten Programmes in diesem Programm nicht mehr möglich sind, also sind die Zeilen 52 bis 55 auskommentiert. Auch hier ist es vielleicht schwierig, die Sinnhaftigkeit des ganzen in einem so einfachen Programm zu erkennen. In einem umfassenden Programm macht sich die Verwendung des Compilers, um sicherzustellen, daß die Regeln eingehalten werden, aber sehr bezahlt.

Obwohl Quadrat und Box beide Objekte der Klasse Rechteck sind, sind ihre privaten Daten vor dem jeweils anderen Objekt versteckt, sodaß keines absichtlich oder unabsichtlich die Daten des anderen verändern kann.

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

Zum Beispiel Datenschutz:

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

Das ist der abstrakte Datentyp, von dem wir am Beginn dieses Kapitels gesprochen haben, ein Modell mit privaten Variablen, um Daten zu speichern, und Operationen, die mit diesen Daten ausgeführt werden können. Die einzigen Operationen, die mit den Daten arbeiten können, sind die Methoden, was viele Fehler, die allzu leicht passieren, verhindern hilft. Der Zugriffsschutz bindet die Daten und die Prozeduren, oder Methoden, eng aneinander und schränkt den Gültigkeitsbereich und die Sichtbarkeit beider ein. Auch hier treffen wir auf die Taktik "teile und herrsche", mit der ein Objekt vom Rest des Codes abgesondert und von diesem komplett isoliert entwickelt wird. Dann erst wird es in den Rest des Codes mit Hilfe einiger einfacher Schnittstellen eingebaut.

Eine Studie hat vor einigen Jahren gezeigt, daß Programmiererinnen viel eher bei Daten Fehler machen als bei Code. Also war es klar, daß man die Qualität von Software alleine schon dadurch würde verbessern können, daß man die Daten vor unabsichtlichen Veränderungen schützt. Das ist der Ursprung des Zugriffsschutzes und diese Idee hat sich im Laufe der Jahre sehr bewährt.

Hast Du diese Technik schon einmal benutzt?

Ein recht gutes Beispiel für diese Technik geben die Dateibearbeitungsbefehle in ANSI-C ab. Du kannst auf die Daten in einer Datei nur über den "Umweg" der Funktionen, die Dein Compiler dafür zur Verfügung stellt, zugreifen. Du hast keinen direkten Zugriff auf die eigentlichen Daten, weil es Dir unmöglich wäre, diese zu adressieren. Daher sind diese Daten private Daten, und die Funktionen sind den Methoden von C++ sehr ähnlich.

Zwei Aspekte dieser Technologie sind in der Softwareentwicklung besonders wichtig. Erstens bekommst Du alle Daten, die sie brauchen, vom System, da die Schnittstelle komplett ist und alles abdeckt, zweitens aber bekommst Du keine Daten, die Du nicht brauchst. Du wirst davor abgehalten (oder bewahrt), in das Dateimanagement einzugreifen und möglicherweise Unfug anzustellen und dabei Daten zu verlieren. Du kannst auch nicht die falschen Daten verwenden, da die Funktionen einen seriellen Zugriff auf diese verlangen. Daß es sich bei diesem Beispiel aber um ein relativ schwaches handelt, sieht man daran, daß es für eine versierte C Programmiererin ein Leichtes ist, den Zugriffsschutz zu umgehen.

Ein weiteres Beispiel für einen schwachen Zugriffsschutz sind die Bildschirm- und Tastaturroutinen. Du kannst in deren Arbeit nicht eingreifen, hast aber über Schnittstellen auf alle Daten Zugriff, die Du benötigst, um sie effizient zu verwenden.

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

Zum Beispiel Nutzbringendes:

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

Stell Dir vor, Du entwickelst ein Programm, das die Charakteristika von Fahnenmasten analysiert. Du würdest nicht unbedingt irgendwelche Daten, die angeben, wo Dein Programm gespeichert ist, als die Höhe eines Fahnenmasten verwenden wollen oder die Cursorposition als des Fahnenmasten Dicke oder Farbe. Der gesamte Code für den Fahnenmasten wird separat entwickelt und erst wenn er fertig ist, kann er auch verwendet werden. Für die Verwendung genügen dann einige wenige Operationen mit der Klasse. Die Tatsache, daß die Daten vor Dir sicher verwahrt und versteckt sind, bewahrt Dich vor "Dummheiten", wenn Du um 2 Uhr früh arbeitest, um irgendeine deadline (heißt nicht umsonst so) einzuhalten. Dies wird Zugriffsschutz genannt und ist einer der großen Vorteile, die objektorientiertes gegenüber prozeduralem Programmieren hat.

Wie aus dem oben gesagten deutlich wird, ist objektorientiertes Programmieren als solches nicht wirklich neu, in einigen wenigen und kleinen Punkten wird es verwendet, seit es Computer gibt. Die neueste Entwicklung ist es allerdings, der Programmiererin die Möglichkeit zu geben, daran teilzuhaben und ihre Programme zu partionieren, um die Fehleranfälligkeit zu verringern und die Qualität zu erhöhen.

Welche Nachteile gibt es?

Es sollte klar sein, daß diese Technik die Effizienz der Programme etwas leiden läßt, da jeder Zugriff auf ein Element der Klasse die Zeit und Ineffizienz eines Funktionsaufrufes, oder dann eher Methodenaufrufes, benötigt. Die Zeit, die beim Kompilieren verloren geht, ist aber bei der Fehlersuche schnell wettgemacht, da ein Programm, das aus Objekten besteht, wesentlich einfacher und schneller zu verstehen ist.

Dieses Programm ist so einfach, daß es unsinnig ist, nachzuforschen, wo wir möglicherweise profitiert haben. In einem wirklichen Projekt kann es ein großer Gewinn sein, wenn eine Entwicklerin all die Details des Rechtecks entwickelt, programmiert und dann zur Verfügung stellt. Genau das ist schon für Dich gemacht worden, wenn Du Dir den Monitor als Objekt vorstellst. Es gibt ein komplettes Arsenal an programmierten und fehlerbereinigten Routinen, die Du verwenden kannst, um am Bildschirm das zu tun, was Du willst. Alles, was Du tun mußt, ist, die Schnittstelle zu benutzen lernen und Dich darauf verlassen, daß die Funktionen auch funktionieren. Du mußt Dir die Implementation nicht ansehen oder sie gar verstehen, vorausgesetzt, es funktioniert alles so, wie Du es Dir vorstellst. Es ist Dir nicht möglich, die Größe Deines Bildschirms mit der Tiefe des Fahnenmasten zu multiplizieren, einfach weil Du die Informationen dazu nicht hast.

Wenn Du die Vorteile dieses Programmierstils verstanden hast kompiliere das Programm und führe es aus (Oper?).

Konstruktoren und Destruktoren

Beispielprogramm: KONSMAST.CPP

Das Programm KONSMAST.CPP soll uns jetzt mit Konstruktoren und Destruktoren bekannt machen.

Bis auf die Tatsache, daß wir einen Konstruktor und einen Destruktor hinzugefügt haben, ist dieses Beispielprogramm identisch mit dem letzten. In Zeile 9 deklarieren wir den Konstruktor, der immer denselben Namen hat wie die Klasse selbst, und in den Zeilen 15 bis 19 definieren wir ihn. Der Konstruktor wird vom C++ System automatisch aufgerufen, wenn ein Objekt deklariert wird und verhindert die Verwendung von uninitialisierten Variablen. Wenn wir also in Zeile 48 das Objekt mit dem Namen Box deklarieren, ruft das System automatisch den Konstruktor auf. Der Konstruktor setzt die zwei Variablen, Hoehe und Breite, im Objekt mit dem Namen Box beide auf den Wert 6 . Zur Kontrolle geben wir das in den Zeilen 51 und 52 aus. Genauso werden bei der Deklaration vom Quadrat die Werte für die Hoehe und die Breite des Quadrat durch den Konstruktor beide mit 6 initialisiert.

Ein Konstruktor hat der Definition nach denselben Namen wie die Klasse selbst. In diesem Fall heißen beide Rechteck. Die Definition von C++ verbietet einen Rückgabewert des Konstruktors. Eigentlich hat er einen vordefinierten Rückgabetyp, nämlich einen Zeiger auf das Objekt selbst, das soll uns aber bis sehr viel später in dieser Einführung nicht kümmern. Obwohl beiden Objekten durch den Konstruktor Werte zugewiesen werden, initialisieren wir sie in den Zeilen 60 und 61 mit neuen Werten. Da wir einen Konstruktor haben, der die Initialisierung übernimmt, sollten wir der Methode Initialisiere() vielleicht einen anderen Namen geben, das Konzept illustriert sie aber auch so.

Der Destruktor ist dem Konstruktor sehr ähnlich, nur wird er aufgerufen, wenn ein Objekt nicht mehr gültig ist. Du wirst sich erinnern, daß automatische Variablen eine beschränkte Lebensdauer haben, da ihre Tage gezählt sind, sobald das Programm den Block, innerhalb dessen sie deklariert wurden, verläßt. Gerade bevor dies geschieht wird der Destruktor aufgerufen, so einer existiert. Ein Destruktor hat denselben Namen wie die Klasse selbst mit einer Tilde davor. Ein Destruktor hat keinen Rückgabewert.

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

Zum Beispiel objektorientiertes Herz:

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

Wir deklarieren einen Destruktor in Zeile 12 und definieren ihn in den Zeilen 32 bis 36. In diesem Fall weist der Destruktor nur den Variablen jeweils den Wert 0 zu bevor ihr Speicherplatz freigegeben wird, es passiert also im Grunde gar nichts. Der Destruktor wurde nur hinzugefügt, um zu zeigen, wie er verwendet wird. Wenn innerhalb des Objektes dynamisch Speicherplatz beschafft wurde, sollte der Destruktor diesen freigeben, bevor die Zeiger darauf verloren gehen. Damit ist ihr Speicherplatz für weitere Verwendung verfügbar.

Es ist interessant zu wissen, daß ein Konstruktor für ein Objekt, das vor der Funktion main() deklariert wird, eine globale Variable also, auch vor der Funktion main() abgearbeitet wird. Genauso wird ein Destruktor für ein solches Objekt nach dem Abarbeiten der Funktion main() aufgerufen. Das hat zwar auf Dein Programm keinen wesentlichen Einfluß, ist aber doch recht interessant.

Modulare Gestaltung

Beispielprogramm: BOXEN1.CPP

BOXEN1.CPP gibt ein Beispiel, wie modulare Gestaltung nicht aussehen soll. Für ein sehr kleines Programm kann das ja ganz nett sein, es soll Dir aber zeigen, wie Du Dein Programm auf kleinere, leichter handhabbare Dateien aufteilst, wenn Du ein größeres Programm entwickelst oder Teil eines Teams bist, das solches tut. Die nächsten drei Beispielprogramme in diesem Kapitel werden zeigen, wie modulare Gestaltung ungefähr aussehen sollte.

Dieses Programm ähnelt dem letzten. Wir haben die Struktur Mast weggelassen und die Klasse heißt jetzt Box. Die Klasse wird in den Zeilen 4 bis 13 deklariert, in den Zeilen 16 bis 35 erfolgt ihre Implementation und wir verwenden die Klasse in den Zeilen 38 bis 52. Mit den Erklärungen zum letzten Programm sollte das Verständnis dieses Beispiels keine Schwierigkeiten bereiten.

Inline-Elementfunktionen

Da die Methode in Zeile 11 sehr einfach ist (und weil wir damit einer weitere Neuerung in C++, die Du oft verwenden wirst, begegnen), ist die Implementation der Methode Teil der Deklaration. Wenn die Implementation in der Deklaration steht, erfolgt die Abarbeitung ohne Funktionsaufruf, was zu wesentlich schnellerem Code führt. In manchen Fällen führt das zu Code, der sowohl kleiner als auch schneller ist, ein weiteres Beispiel für die Effizienz von C++. Solche inline-Elementfunktionen haben dieselbe Effizienz wie Makros in C und ihnen ist bei kleinen Funktionen der Vorzug zu geben.

Kompiliere das Programm und führe es aus als Vorbereitung auf die nächsten drei Beispiele, Wiederholungen dieses Programmes in einer etwas anderen Form.

Die header-Datei der "Box" Klasse

Beispielprogramm: BOX.H

Wenn Du Dir die Datei BOX.H genau ansiehst, wirst Du feststellen, daß es sich dabei lediglich um die Klassendefinition handelt. Hier findet sich nichts über die Details der Implementation, die inline-Elementfunktion HoleFlaeche() natürlich ausgenommen. Wir finden in dieser Datei die komplette Definition, wie die Klasse verwendet wird, ohne mit der Implementation der Methoden in Berührung zu kommen. Drucke diese Datei aus, sie wird nützlich sein, wenn wir uns die nächsten beiden Dateien ansehen. Diese Datei enthält die Zeilen 4 bis 13 des vorigen Beispielprogrammes, BOXEN1.CPP. Es wird die header-Datei der Klasse genannt und kann weder kompiliert noch ausgeführt werden.

Die Implementation der "Box" Klasse

Beispielprogramm: BOX.CPP

Im Programm BOX.CPP findet sich die Implementation der Methoden, die wir in der header-Datei deklariert haben. In Zeile 2 importieren wir diese Datei mit den Prototypen der Methoden und den Definitionen der Variablen auch. Die Zeilen 16 bis 35 der Datei BOXEN1.CPP finden wir in dieser Datei, der Implementation der Methoden, die wir für die Klasse Box deklariert haben, wieder.

Zwar können wir diese Datei kompilieren, ausführen können wir sie aber nicht, da sie keine Funktion main() enthält, den Einstiegspunkt, den jedes ANSI-C oder C++ Programm benötigt. Nach dem Kompilieren wird der Objektcode im aktuellen Verzeichnis gespeichert und steht zur weiteren Verwendung durch andere Programme bereit. Das Ergebnis eines Kompiliervorganges wird üblicherweise Objektdatei genannt, da sie Objektcode beinhaltet. Das Wort Objekt in diesem Sinn hat aber nichts damit zu tun, was wir unter einem Objekt verstehen, wenn wir von objektorientiertem Programmieren sprechen. Es wird einfach die Bedeutung des Wortes "überladen". Die Sitte, das Resultat des Kompilierens als Objektdatei zu bezeichnen gibt es schon wesentlich länger als das Konzept des objektorientierten Programmierens.

Die Trennung von Definition und Implementation ist ein wesentlicher Schritt vorwärts in der Entwicklung von Software. Die Programmiererin benötigt lediglich die Datei mit der Definition, um die Klasse effektiv in seinen Programmen einsetzen zu können. Sie muß nicht wissen, wie die einzelnen Methoden realisiert sind. Wenn ihr die Implementation zur Verfügung stünde, könnte sie diese studieren und möglicherweise den einen oder anderen Trick finden, wie sie ihr Programm etwas effizienter gestalten kann, das würde aber zu nicht portierbarem Code und leicht zu Fehlern führen, wenn die Autorin der Klasse die Implementation modifiziert, ohne die Schnittstellen zu ändern. Der Sinn und Zweck von objektorientiertem Programmieren ist es, die Implementation so zu verstecken und abzusondern, daß sie nichts außerhalb ihres kleinen Bereiches innerhalb der Schnittstelle beeinflussen kann.

Du solltest die Implementation nun kompilieren. Wir werden das Resultat im nächsten Beispielprogramm verwenden.

Wir verwenden das "Box" Objekt

Beispielprogramm: BOXEN2.CPP

Wirf einen Blick auf die Datei mit dem Namen BOXEN2.CPP und Du wirst sehen, daß wir in diesem Beispiel die zuvor definierte Klasse verwenden. Die letzten drei Dateien zusammen sind identisch mit dem Programm BOXEN1.CPP, das wir uns vorher angesehen haben.

In Zeile 3 importieren wir die header-Datei BOX.H, da wir die Definition der Klasse Box benötigen, um die drei Objekt deklarieren und ihre Methoden verwenden zu können. Du solltest gleich erkannt haben, daß es sich um nichts als eine Kopie des letzten Programmes handelt und auch genau dasselbe tut. Es gibt aber einen gewichtigen Unterschied zwischen BOXEN1.CPP und BOXEN2.CPP, wie wir gleich sehen werden.

Wir müssen hier eine wesentliche Unterscheidung machen. Wir rufen nicht einfach Funktionen auf und nennen daß halt jetzt das Senden von Nachrichten. Es gibt einen wesentlichen Unterschied in den Aktionen selbst. Da die Daten eines Objektes eng an dieses gebunden sind gibt es keinen anderen Weg, an diese Daten zu kommen, als mit Hilfe der Methoden. Also senden wir eine Nachricht an das Objekt, die ihm mitteilt, daß es etwas mit den internen Daten anstellen soll. Wannimmer wir allerdings eine Funktion aufrufen, geben wir ihr die Daten, mit denen sie arbeiten soll, als Parameter mit. Eine Funktion hat keine eigenen Daten. Zugegeben, der Unterschied ist vielleicht ein geringer, wir werden aber die neue Terminologie verwenden und Dir sollte klar sein, daß eben doch ein Unterschied besteht.

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

Zum Beispiel Objekte verwenden:

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

Kompiliere dieses Programm und führe es aus. Wenn es ans linken geht, mußt Du dieses Programm mit dem Resultat der Kompilation der Klasse mit dem Namen Boxen linken. Die Datei heißt möglicherweise BOX.O. Dein Compiler hält sicherlich Informationen bereit, wie Du das anstellst.

Dieses Programm ist die erste Gelegenheit, eine Projekt-Datei oder "make" zu verwenden. Egal welchen C++ Compiler Du benutzt, es ist die Zeit wert, wenn Du Dir jetzt ansiehst, wie das funktioniert. Wir werden das im Laufe dieser Einführung noch des öfteren benötigen. Es liegt in der Natur von C++, die Programmiererin dazu anzuhalten, viele Dateien für ein Projekt zu verwenden und Du solltest Dich so bald wie möglich daran gewöhnen.

Ein Versteckspiel

Die drei Beispielprogramme, die wir uns zuletzt angesehen haben, illustrieren eine Methode des Zugriffsschutzes, die eine großen Einfluß auf die Qualität der Software haben kann, die für ein großes Projekt entwickelt wird. Da alle Information, die die Benutzerin einer Klasse benötigt, in der header-Datei zu finden ist, bekommt sie auch nicht mehr als diese zu sehen. Die Details der Implementation werden vor ihr versteckt, um sie davor abzuhalten, diese zu studieren und irgendeinen Kunstgriff zu tun, der zu unsauberem Code führt. Da sie nicht genau weiß, was diejenige, die die Klasse geschrieben hat, implementiert hat, muß sie sich an die Definitionen, die die header-Datei gibt, halten. Das kann, wie gesagt, einen großen Einfluß auf ein großes Projekt haben. Darüber hinaus wird die irrtümliche Änderung von Daten verhindert.

Ein weiterer Grund, die Implementation zu verstecken, ist ein wirtschaftlicher. Der Hersteller Deines Compilers hat Dir viele Bibliotheksfunktionen zur Verfügung gestellt, nicht jedoch deren Quellcode, nur die Schnittstelle zu jeder Funktion. Du weißt, wie die Funktionen zum Dateizugriff zu verwenden sind, nicht jedoch deren Implementation und Du brauchst diese auch gar nicht. Es kann auch eine Bibliotheken-Industrie entstehen, die Programmiererinnen für eine Lizenzgebühr fix und fertig programmierte und getestete Bibliotheken von hoher Qualität zur Verfügung stellt. Da die Programmiererin nur die Definition der Schnittstelle benötigt, erhält sie diese zusammen mit dem Objektcode (dem Ergebnis des Kompiliervorganges) der Klasse und kann diese nach Herzenslust verwenden. Der Quellcode der Autorin der Klasse ist vor unabsichtlichen oder absichtlichen Modifikationen geschützt und die Autorin behält die volle Kontrolle über ihn.

Es ist wichtig, daß Du die Prinzipien dieses Kapitels verstanden hast, bevor Du zum nächsten weitergehst. Wenn Du Dir über irgendetwas noch nicht vollkommen im Klaren bist, wirf noch einmal einen (genaueren) Blick darauf. Etwas sei noch erwähnt, falls Du es noch nicht selbst bemerkt hast: um eine Klasse effektiv zu verwenden, bedarf es einigen Weitblicks.

Abstrakte Datentypen

Wir haben den sogenannten abstrakten Datentyp am Beginn dieses Kapitels erwähnt und noch einmal etwas später. Jetzt ist es an der Zeit, etwas genauer darauf einzugehen. Ein abstrakter Datentyp ist eine Gruppe von Daten, von denen jede eine Reihe von Werten speichern kann, und einigen Methoden oder Funktionen, die mit diesen Daten arbeiten. Die Daten sind vor äußerem Zugriff geschützt. Da die Daten eine Beziehung zueinander haben, bilden Sie eine zusammenhängende Gruppe, deren Mitglieder miteinander sehr viel zu tun haben, aber wenig mit der "Außenwelt".

Die Methoden allerdings haben eine Verbindung zu dieser Außenwelt über die Schnittstellen, die Zahl der Kontakte ist aber beschränkt und die Verbindung mit dem übrigen Programm ist eine lose. Das Objekt ist lose mit der Außenwelt verbunden. Durch die enge Verbindung untereinander einerseits und die lose Bindung zur Außenwelt andererseits wird die Wartung von Software erleichtert. Das ist vielleicht der größte Vorteil objektorientierten Programmierens.

Es macht Dir vielleicht Sorgen, daß die Programmiererin die privaten Variablen zwar außerhalb der Klasse nicht verwenden kann, sie aber doch zu Gesicht bekommt und so eventuell ziemlich genau abschätzen kann, wie die Klasse implementiert ist. Die Variablen hätten ohne weiteres komplett in einer anderen Datei versteckt werden können. Da die Autoren von C++ aber auf Effizienz großen Wert gelegt haben, blieben die Variablen in der Klassendefinition, wo sie zwar sichtbar, aber nicht brauchbar sind.

Freundfunktionen in C++

Eine Funktion außerhalb der Klasse kann als friend-Funktion der Klasse definiert werden und so Zugriff auf die privaten Elemente der Klasse erhalten. Das öffnet das Schutzschild rund um die Daten der Klasse ein wenig, sollte also nur sehr selten angewendet werden. Es gibt Fälle, wo ein Programm durch die Verwendung solcher Freundfunktionen leichter zu verstehen ist und diese einen kontrollierten Zugriff auf die Daten erlauben. Wir werden die Verwendung von Freundfunktionen in einigen Beispielprogrammen später in dieser Einführung zeigen. Wir haben sie hier aber der Vollständigkeit halber erwähnt. Du kannst einer einzelnen Funktion diesen Status verleihen, aber auch Elementen anderer Klassen oder gar ganzen Klassen. Weder ein Konstruktor noch ein Destruktor kann allerdings aus verständlichen Gründen eine Freundfunktion sein.

Die Struktur in C++

Strukturen (Schlüsselwort struct) sind in C++ nach wie vor enthalten und verhalten sich genauso wie in ANSI-C. Du kannst Deiner Struktur Methoden geben, die mit den Daten genauso arbeiten wie in einer Klasse, aber Methoden wie Daten sind am Anfang einer Struktur automatisch öffentlich. Selbstverständlich kannst Du die Daten oder Methoden als privat deklarieren. Eine Struktur sollte aber nur für Konstrukte verwendet werden, die auch wirklich Strukturen sind. Wenn Du auch nur einfachste Objekte konstruierst, solltest Du eine Klasse dafür verwenden.

Eine sehr praktische C++ Klasse: Datum

Die Beispiele, die wir in diesem Kapitel für Zugriffsschutz gegeben haben, waren all sehr einfach, um zu zeigen, wie es grundsätzlich funktioniert. Da es aber sicherlich nicht schadet, auch ein etwas größeres Beispiel gesehen zu haben, sehen wir uns als nächstes die Klasse Datum an. Diese Klasse ist ein komplettes und brauchbares Beispiel. Du kannst sie in jedem Programm verwenden, um das aktuelle Datum in einem von vier vordefinierten Formaten auszugeben. Du kannst sie auch verwenden, um ein Datum zu speichern und für die Ausgabe zu formatieren.

Beispielprogramm: DATUM.H

Die Datei mit dem Namen DATUM.H ist die header-Datei für unsere Klasse Datum. Sie ist reichhaltigst kommentiert, sodaß nicht viel zu sagen bleibt. Wenn Du im Prinzip verstanden hast, was wir in diesem Kapitel behandelt haben, solltest Du auch mit dieser Klasse keine Probleme haben. Neu für Dich ist das geschützte Wort protected in Zeile 13. Wir werden dieses Wort ein paar Kapitel weiter hinten definieren. Bis dahin nimm an, daß es dasselbe meint wie private, das genügt einstweilen fürs Verständnis dieses Beispiels. Den Code in den Zeilen 8,9 und 57 werden wir gleich erklären. Mißachte diese Zeilen einstweilen einfach. Auch dem Schlüsselwort static wie es in den Zeilen 18 und 19 verwendet wird, werden wir uns später widmen. Diese neuen Konstrukte haben wir deshalb eingefügt, weil wir diese Klasse später beim Studium der Vererbung verwenden wollen.

Du solltest Dich so lange mit der header-Datei befassen, bis Du bis auf die oben genannten neuen Konstrukte alles verstanden hast. Geh dann weiter zur Implementation der Klasse.

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

Zum Beispiel praktisch:

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

Beispielprogramm: DATUM.CPP

Die Datei mit dem Namen DATUM.CPP beinhaltet die Implementation der Datum Klasse. Auch hier findet sich nichts Außergewöhnliches oder Schwieriges. Sie verwendet einfache Konstrukte, um das Datum zu speichern und in einer brauchbaren Form auszugeben. Du sollten auch diesen Code so lange studieren, bis Du ihn komplett verstanden hast, bevor Du zum nächsten Beispiel weitergehst, wo wir die Datum Klasse in einem Programm verwenden werden.

Die Implementation des Konstruktors in den Zeilen 14 bis 25 verwendet Systemaufrufe, um das aktuelle Datum zu bekommen. Diese Aufrufe werden nur kompilieren, wenn sie 16-Bit DOS verwenden, da sie nicht kompatibel sind. Du kannst diese Zeilen so abändern, daß sie die Aufrufe Deines Systems verwenden oder den Elementvariablen einfach beliebige Werte zuweisen. Sinn und Zweck dieses Codes ist es, die Verwendung von Zugriffsschutz und Konstruktoren zu zu illustrieren, nicht das Auslesen der Uhr und des Kalenders Deines Computers.

Beispielprogramm: VERWDAT.CPP

Im einfachen Programm VERWDAT.CPP verwenden wir die Datum Klasse, um das aktuelle und ein weiteres Datum am Bildschirm auszugeben. Du solltest kein Problem mit dem Verständnis dieses Programmes haben, also wollen wir auch keine weiteren Worte darüber verlieren.

Du solltest Dir genug Zeit nehmen, diese drei Dateien zu verstehen, da sie den Ausgangspunkt einer Anschauungsreise in den nächsten Kapiteln bilden. Wir werden diese Klasse in Verbindung mit anderen verwenden, um einfache und vielfache Vererbung zu demonstrieren. Auch wenn Du nicht jede Einzelheit des Programmes verstehst, solltest Du doch versuchen, die Struktur und die wesentlichen Konzepte zu verstehen.

Wir werden die Diskussion des Zugriffsschutzes im nächsten Kapitel fortsetzen.

Programmieraufgaben

  1. Füge zu KLAS.CPP eine Methode hinzu, die das Quadrat des gespeicherten Wertes zurückgibt. Erweitere das Hauptprogramm um Code, der den quadrierten Wert liest und ausgibt.
  2. Erweitere KLAS.CPP weiters um einen Konstruktor, der den gespeicherten Wert mit 10 initialisiert. Schreibe im Hauptprogramm einige Zeilen Code, die die Werte unmittelbar nach der Definition des Objektes ausgeben.
  3. Füge dem Konstruktor von Rechteck in KONSMAST.CPP eine Bildschirmausgabe hinzu und eine weitere zum Destruktor, um zu zeigen, daß diese wirklich aufgerufen werden.
  4. Schreibe eine etwas anspruchsvollere Anwendung für die Klasse Datum, die wir am Ende des Kapitels vorgestellt haben.
  5. Schreibe eine Klasse mit dem Namen Name, die ähnlich der Klasse Datum jeden beliebigen Namen in drei Teilen speichern kann und den vollständigen Namen dann in einer Reihe von Formaten ausgeben kann, wie zum Beispiel
    Heinz Heinzl Tschabitscher
    H. H. Tschabitscher
    Tschabitscher, Heinz Heinzl

    oder was immer Dir zusagt.

(weiter »)

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

Zum Beispiel Zukunftsschutz:

Langlebige Software-Architekturen: Technische Schulden analysieren, begrenzen und abbauen
Die Komplexität ist eine Tochter von Software und Zeit. Dass man alten Code nicht mehr angreifen will (weil man ihn nicht versteht), ist allerdings nicht notwendig so. "Langlebige Software-Architekturen" liefert sehr praxisorientiert — mit realen Fallbeispielen — und theoretisch fundiert — mit Einblicken in die kognitiven Prozesse, die uns komplizierte System verstehen lernen — brauchbares Wissen zum spannenden Thema Softwarearchitektur.
›› Mehr Softwareentwicklung-Bücher

[ ist: ]