Mit HTML einen Index erstellen - so geht’s


/* da der zweite Index für die Spalte Zur Abschreckung zeigen wir einmal den Aufwand für die Initialisierung Wie Sie sehen, muss für jede.

Geben Sie eines der oben gezeigten Beispiele ein. Teilen Sie dies einfach in schriftlicher Form dem Versicherer mit.

Jetzt anfordern!

 · Wenn Sie den Index dennoch für die Suche aktivieren möchten, Dokumentennummer und Dokumentkennung definieren, wenn Sie den Index erstellen.

Bei zeitlich vor der Inflation abgeschlossenen Verträgen verschiebt sich das wirtschaftliche Gleichgewicht. So wird generell der Schuldner besser gestellt, während sich die Position des Gläubigers verschlechtert. Das gilt zum Beispiel für Mieten, Unterhaltszahlungen, Renten- und Pensionsansprüche und Honorarforderungen aufgrund gesetzlich geregelter Honorarordnung wie bei Rechtsanwälten und Ärzten. So wurden die Immobilienbesitzer beispielsweise in der Deutschen Inflation bis faktisch vollständig entschuldet, während die Immobilien den Wert beibehielten.

Der Gesetzgeber versuchte, diese Inflationsgewinne über die Hauszinssteuer abzuschöpfen. Der Realwert seiner Verschuldung nimmt wegen der Inflation deutlich ab. Durch kalte Progression steigen zudem die realen Steuereinnahmen.

Bei schwerer Inflation steigt auch die Umlaufgeschwindigkeit des Geldes, denn da das Geld ständig entwertet wird, will niemand es lange behalten. Kann nicht genug werthaltiges Sachkapital produziert werden, wird versucht, Wert in Devisen anzulegen. Die Entwertung des Geldes wird so beschleunigt. Versucht der Staat, die freie Preisbildung zu regulieren, entsteht statt offener verdeckte oder zurückgestaute Inflation. Im Falle flexibler Wechselkurse erfolgt eine Anpassung durch Abwertung des Wechselkurses der inländischen Währung gegenüber ausländischen Währungen.

Bei festen Wechselkursen erfolgt keine automatische Korrektur. Ist die Inflationsrate höher als in anderen Ländern, verbilligen sich die Importe, die Exporte verteuern sich. Dies führt zu Handelsbilanzdefiziten. Je nach Stärke und Tempo der Preissteigerung unterscheidet man zwischen schleichender Inflation, trabender Inflation, galoppierender Inflation und Hyperinflation.

Die Inflation kann man in Phasen einordnen: Die dezelerierte Phase wird auch als Disinflation bezeichnet. Heute wird er losgelöst von der tatsächlichen Geschwindigkeit der Erhöhung des Preisniveaus in einem Land gebraucht. Es kommt zur Flucht in wertstabile Sachwerte und zu Kapitalflucht. Auf den Kapitalmärkten nimmt das Kapitalangebot ab, da die Anbieter wegen der Inflation mit einem Werteverzehr rechnen, der Kapitalzins steigt.

Aus gleichem Grund werden langfristige Kredite kaum noch angeboten, schon gar nicht mit festem Zins. So besteht auch für Kreditnehmer keine Planungssicherheit mehr. Bisher knapp lohnende Investitionen werden durch Zinssteigerung unrentabel; Unternehmen, deren Rendite nicht mehr ausreicht, gehen bankrott.

Hyperinflationen kamen in der Geschichte schon mehrmals auch deshalb zum Stillstand, weil selbst der Realwert des Papiers zum Drucken der Banknoten höher war als der Wert einer Banknote. Häufig gibt es nach einer Hyperinflation eine Währungsreform. Den historisch ältesten Erklärungsansatz für Inflation bietet die Quantitätsgleichung:. Empirisch ist die Quantitätstheorie sehr gut belegt. Diese Untersuchungen zeigen, dass Inflation entsteht, wenn die Zentralbank die Geldmenge zu stark ausweitet.

Im Umkehrschluss bedeutet dies, dass Inflation durch eine restriktive Geldpolitik verhindert werden kann. Durch zyklisches und unkontrolliertes Geldwachstum entstünden Kredite ex nihilo mit künstlich niedrigen Zinsraten. Durch die Inflation und die Kreditexpansion würde das gesamte Preissystem verzerrt, der Preis verliere seine Funktion der Information über Knappheit, unproduktive Produktionsweisen würden dadurch künstlich am Leben gehalten.

Neu geschaffenes Geld gelangt von den Zentral- und Geschäftsbanken zu Marktteilnehmern , die mit diesem neuen Geld Güter nachfragen. Diese zusätzliche Nachfrage wird in steigenden Preisen sichtbar. Die Ursache für Inflation ist damit in der Schöpfung von ungedecktem Geld so wie in gesetzlich privilegierten Institutionen des Bank - und Finanzwesens zu finden Annahmezwang von Gesetzlichen Zahlungsmitteln , Zentralbankwesen , Teilreservebanken , Währungsmonopol usw.

Grundsätzlich wird hierbei zwischen einer Nachfragesoginflation und einer Angebotsdruckinflation unterschieden. Kommt es zur Nachfragesoginflation englisch Demand-pull inflation , [21] sind die Ursachen, wie aus dem Wort zu entnehmen, auf der Nachfrageseite zu suchen.

Betrifft dies alle Güter, ist jedoch ceteris paribus aggregiert ein Preisanstieg nicht möglich. Erfolgt eine monetäre Alimentierung, entsteht Inflation. Kurzfristig kann diese Alimentierung durch eine Erhöhung der Umlaufgeschwindigkeit des Geldes erfolgen. Längerfristig kann Inflation aber nur bestehen, wenn sie durch eine entsprechende Ausweitung der Geldmenge alimentiert wird. Auf der anderen Seite steht die Angebotsdruckinflation auch: Die Kosteninflation tritt allerdings nur dann als Erhöhung des Preisniveaus in Erscheinung, wenn die teurer produzierten Güter auch auf dem Markt zu den geforderten höheren Preisen Käufer finden und es keine Substitution aus anderen Märkten gibt Verkäufermarkt.

Auch diese Inflationsart kann nur bei einer entsprechenden Ausweitung der Geldmenge längerfristig bestehen. Besonderen Sinn ergibt die Indexanpassungen bei langfristigen Verträgen - ein Beispiel:. Sie haben vor 20 Jahren eine Eigenheimversicherung mit einer Höchstentschädigungssumme Versicherungssumme von Durch die Geldentwertung bzw.

Aber auch schon bei höheren Teilschäden könnte ein Schadensgutachter eine Unterversicherung feststellen und aliquot geltend machen. Der Index ist also bei vielen Sachversicherungen Haushaltsversicherung, Eigenheimversicherung u. Denn sonst könnte ob der Inflation eine ziemliche Pensionslücke entstehen Dies gilt für eine ganze Reihe von Versicherungsprodukten. Je länger die Laufzeit eines Vertrages ist, desto wesentlicher wird der Index.

Normalerweise ist der Index in den meisten Produkten ohnehin automatisch dabei - Sie können diesbezüglich also gar nicht viel falsch machen. Hier könnte die zweite Variante verwendet werden, jedoch besitzt der Konstruktor zwei Parameter, daher ist die Variante mit dem Gleichheitszeichen nicht sofort offensichtlich. Dieses Thema wird am Ende des Kapitels genauer besprochen, da zum Verständnis dessen ein wenig Hintergrundwissen nötig ist, das im Verlauf des Kapitels vermittelt wird.

Beachten Sie, dass die Initialisierung der Variablen einer Klasse in der Reihenfolge erfolgt, in der sie in der Klasse deklariert wurden. Die Initialisierungsreihenfolge ist unabhängig von der Reihenfolge, in der sie in der Initialisierungsliste angegeben wurden.

Viele Compiler warnen, wenn man so etwas macht, da derartiger Code möglicherweise nicht das tut, was man erwartet. Natürlich ist es wie bei Funktionen möglich und in der Regel zu empfehlen, die Methodendeklaration von der Methodendefinition zu trennen. Die Definition sieht genau so aus, wie bei einer normalen Funktion. Der einzige auffällige Unterschied besteht darin, dass dem Methodennamen der Klassenname vorangestellt wird, getrennt durch den Bereichsoperator:: Wie bereits erwähnt, hat der Konstruktor keinen Rückgabetyp, daher wird auch in der Definition keiner angegeben.

Bei den Basisdatentypen ist es bezüglich der Performance übrigens egal, ob Sie diese initialisieren oder zuweisen. Sie könnten also den gleichen Effekt erzielen, wenn Sie statt der Initialisierungsliste eine Zuweisung im Funktionsrumpf benutzen.

Allerdings gilt dies wirklich nur für die Basisdatentypen, bei komplexen Datentypen ist die Initialisierung oft deutlich schneller. Nun aber noch mal ein einfaches Beispiel, in dem der Funktionsrumpf des Konstruktors zur Anfangswertzuweisung dient:.

Wie Sie sehen, entfällt der Doppelpunkt, wenn Sie die Initialisierungsliste nicht nutzen. Natürlich können Sie auch Initialisierungsliste und Funktionsrumpf parallel benutzen. Leider gibt es keine Möglichkeit, Arrays zu initialisieren, sie müssen immer im Konstruktorrumpf mittels Zuweisung ihren Anfangswert erhalten. Entsprechend ist es auch nicht möglich, ein Memberarray mit konstanten Daten zu erstellen.

Wenn Sie also zwingend eine Initialisierung benötigen, müssen Sie wohl oder übel Einzelvariablen erstellen oder auf eine array-ähnliche Klasse zurückgreifen. Beides passiert natürlich im Konstruktorrumpf, in der Initialisierungsliste müssen Sie keine Angaben machen. Sie können einem Konstruktor ebenso Defaultparameter vorgeben, wie einer gewöhnlichen Funktion. Die syntaktischen Regeln sind identisch. Auch das Überladen des Konstruktors funktioniert wie das Überladen einer Funktion.

Deklarieren Sie mehrere Konstruktoren innerhalb der Klasse und schreiben für jeden eine Definition:. Wenn mehrere Konstruktoren das gleiche tun, ist es oft sinnvoll, diese gleichen Teile in eine eigene Methode üblicherweise mit dem Namen init zu schreiben. Das ist kürzer, übersichtlicher, meist schneller und hilft auch noch bei der Vermeidung von Fehlern.

Denn wenn Sie den Code nachträglich ändern, dann müssten Sie diese Änderungen für jeden Konstruktor vornehmen. Nutzen Sie eine init -Methode, müssen Sie den Code nur in dieser ändern. Die Konstruktoren bleiben unverändert. Als Standardkonstruktor bezeichnet man einen Konstruktor, der keine Parameter erwartet. Natürlich könnten wir in diesem Beispiel den Konstruktor überladen, um neben dem Standardkonstruktor auch die Möglichkeiten zur Initialisierung mit beliebigen Werten zu haben.

Es bietet sich hier jedoch an, dafür Defaultparameter zu benutzen. Das folgende kleine Beispiel erlaubt die Initialisierung mit einer ganzen Zahl und mit einer gebrochenen Zahl also zwei Ganzzahlen: Neben dem Standardkonstruktor gibt es einen weiteren speziellen Konstruktor, den Kopierkonstruktor: Der Parameter des Kopierkonstruktors ist also immer eine Referenz auf ein konstantes Objekt derselben Klasse. Der Kopierkonstruktor unserer Bruch -Klasse hat folgende Deklaration:.

Beachten Sie, dass ein Kopierkonstruktor immer eine Referenz auf ein Objekt meist ein konstantes Objekt übernimmt. Dies führt zu einer Endlosrekursion beim Kompilieren und ist somit verboten.

Wenn wir keinen eigenen Kopierkonstruktor schreiben, erstellt der Compiler einen für uns. Dieser implizite Kopierkonstruktor initialisiert alle Membervariablen mit den entsprechenden Werten der Membervariablen im übergebenen Objekt. Für den Moment ist diese vom Compiler erzeugte Variante ausreichend. Später werden Sie Gründe kennenlernen, die es notwendig machen, einen eigenen Kopierkonstruktor zu schreiben. Wenn Sie die Nutzung des Kopierkonstruktors verbieten wollen, dann schreiben Sie seine Deklaration in den private -Bereich der Klassendeklaration.

Das bewirkt einen Kompilierfehler, wenn eine nicht-Klassen-Funktion versucht den Kopierkonstruktor aufzurufen. Neben dem Kopierkonstruktor erzeugt der Compiler übrigens auch noch eine Kopierzuweisung, auch zu dieser werden Sie später noch mehr erfahren.

Auch diese können Sie verbieten, indem Sie sie im private deklarieren. Wie dies geht, erfahren Sie im Kapitel zu Operatorüberladung. Im Gegensatz zum Konstruktor, gibt es beim Destruktor immer nur einen pro Klasse. Das liegt daran, dass ein Destruktor keine Parameter übergeben bekommt.

Für den Anfang werden Sie mit dem Destruktor wahrscheinlich nicht viel anfangen können, da es mit den Mitteln, die Sie bis jetzt kennen, kaum nötig werden kann, dass bei der Zerstörung eines Objektes Aufräumarbeiten ausgeführt werden.

Das folgende kleine Beispiel enthält einen Destruktor, der einfach gar nichts tut:. Wenn Sie den Abschnitt über Speicherverwaltung gelesen haben, werden Sie wissen, wie nützlich der Destruktor ist. Im Moment reicht es, wenn Sie mal von ihm gehört haben. Um noch einmal deutlich zu machen, an welchen Stellen Konstruktor und Destruktor aufgerufen werden, geben wir einfach innerhalb der Methoden eine Nachricht aus:.

Bevor wir den Begriff des expliziten Konstruktors klären, soll kurz auf die oben angesprochene zweite syntaktische Möglichkeit zum Konstruktoraufruf eingegangen werden. Diese Variante, einen Konstruktor aufzurufen, ist absolut gleichwertig zu der, die im Kommentar steht. Beachten Sie an dieser Stelle, dass hier keineswegs ein Kopierkonstruktor aufgerufen wird, es handelt sich tatsächlich nur um eine andere syntaktische Möglichkeit.

Im folgenden Beispiel wird eine Klasse String definiert, welche über 2 Konstruktoren verfügt:. Auf die Implementierung der Konstruktoren soll an dieser Stelle nicht eingegangen werden und natürlich wäre feld in einer echten Klasse privat. Der erste Konstruktor erzeugt ein Objekt anhand einer Zeichenkette. Der zweite Konstruktor kann mit einem oder mit zwei Parametern aufgerufen werden. Er erzeugt einen String, der aus anzahl zeichen besteht. Sicher wird Ihnen auffallen, dass für die Initialisierung von str1 und str3 zwar das Gleichheitszeichen verwendet wird, dahinter jedoch kein Objekt der Klasse String folgt.

Für diese syntaktische Möglichkeit muss der Compiler eine sogenannte implizite Konvertierung durchführen. Falls die Klasse über einen Konstruktor mit einem Parameter verfügt, der zu dem des übergebenen Objekts kompatibel ist, wird dieser Konstruktor verwendet.

Kompatibel bedeutet, dass sich das übergebene Objekt in maximal einem Schritt in ein Objekt mit dem Typ des Parameters umwandeln lässt.

Bei str3 wird ein Objekt vom Typ char const übergeben. Der Compiler findet in der Klasse einen Konstruktor, der mit einem int aufgerufen werden kann. Ein char lässt sich direkt in einen int umwandeln. Daher wählt der Compiler diesen Konstruktor aus. Es ist im Falle von str3 jedoch sehr wahrscheinlich, dass eigentlich ein String definiert werden sollte, der aus dem einzelnen Zeichen 'A' besteht und der Programmierer nur übersehen hat, dass die Klasse gar nicht über einen entsprechenden Konstruktor verfügt.

Das Problem wäre gelöst, wenn die implizite Konvertierung nicht stattfinden würde und genau das ist bei expliziten Konstruktoren der Fall. Das Schlüsselwort für die Deklaration lautet explicit. In vielen Fällen ist, wie bei str1 , eine implizite Konvertierung gewünscht, da sie zur besseren Lesbarkeit des Quellcodes beitragen kann. Beachten Sie auch, dass die folgenden beiden Zeilen explizite Konstruktoraufrufe sind und entsprechend durchgeführt werden:.

Die Möglichkeit, einen Konstruktor mittels impliziter Konvertierung aufzurufen, sollte immer dann genutzt werden, wenn das Objekt, das Sie definieren wollen, den übergebenen Wert repräsentiert. In unserem String-Beispiel ist dies bei str1 der Fall. Das erzeugte Objekt repräsentiert den übergebenen String. Im Falle von str2 wird hingegen ein Objekt nach den Vorgaben der übergebenen Parameter erstellt.

Technisch gesehen wird natürlich in beiden Fällen ein Objekt anhand der Parameter konstruiert. Wenn Sie nun beabsichtigen, einen String zu erstellen, der aus dem Zeichen 'A' besteht, würde das erstellte Objekt das Zeichen 'A' repräsentieren. Wenn Sie sich infolgedessen für die Anwendung einer impliziten Konvertierung wie bei str3 entscheiden, wird der Compiler dies dank explizitem Konstruktor mit einer Fehlermeldung quittieren.

Wenn Sie beabsichtigen einen String mit 'A' vielen Zeichen zu konstruieren, dann wählen Sie die explizite Syntax wie bei str4 oder str5. Dies wird Ihr Compiler anstandslos übersetzen. Mit den Schlüsselwörtern public und private wird festgelegt, von wo aus auf eine Eigenschaft oder Methode einer Klasse zugegriffen werden kann.

Auf jene, die als public deklariert werden, kann von überall aus zugegriffen werden, sie sind also öffentlich verfügbar. Typischerweise werden Variablen private deklariert, während Methoden public sind. Eine Ausnahme bilden Hilfsmethoden, die gewöhnlich im private -Bereich deklariert sind, wie etwa die init -Methode, die von verschiedenen Konstruktoren aufgerufen wird, um Codeverdopplung zu vermeiden. Geändert wird der Sichtbarkeitsbereich durch die beiden Schlüsselwörter gefolgt von einem Doppelpunkt.

Alle Member, die darauffolgend deklariert werden, fallen in den neuen Sichtbarkeitsbereich. Zwischen den Sichtbarkeitsbereichen kann somit beliebig oft gewechselt werden. Der implizit private Bereich sollte aus Gründen der Übersichtlichkeit nicht genutzt werden. In diesem Buch folgen wir der Regel, als erstes die öffentlichen Member zu deklarieren und erst danach die privaten.

Die umgekehrte Variante findet jedoch ebenfalls eine gewisse Verbreitung. Entscheiden Sie sich für eine Variante und wenden Sie diese konsequent an. In Zusammenhang mit Vererbung werden Sie noch einen weiteren Sichtbarkeitsbereich kennen lernen. Dieser ist für unsere Zwecke aber noch nicht nötig und wird daher auch erst später erläutert. Eine Struktur, auch Datenverbund genannt, fasst mehrere Variablen zu einem Typ zusammen.

Sie können in einer Struktur also problemlos Methoden deklarieren oder die Zugriffsrechte über die Schlüsselworte public , protected wird später erläutert und private festlegen. Da dieser implizite Zugriffsrechtebereich aber für gewöhnlich nicht genutzt werden sollte, ist dieser Unterschied fast unbedeutend. Im Kapitel über Vererbung werden Sie noch sehen, dass Sie eine Klasse problemlos von einer Struktur ableiten können und umgekehrt.

Auch für Klassen gilt üblicherweise: Verwenden Sie const , wann immer es möglich ist. Wie Sie bereits wissen, sollte const immer verwendet werden, wenn eine Variable nach der Initialisierung nicht mehr verändert werden soll. Da Klassen Datentypen sind, von denen Instanzen also Variablen erstellt werden können, ist es natürlich möglich ein Objekt zu erstellen, das konstant ist.

Da der Compiler jedoch davon ausgehen muss, dass jede Methode der Klasse die Daten und somit das Objekt verändert, sind Methodenaufrufe für konstante Objekte nicht möglich.

Eine Ausnahme bilden jene Methoden, die ebenfalls als const gekennzeichnet sind. Eine solche Methode kann zwar problemlos Daten aus dem Objekt lesen, aber niemals darauf schreiben und auch für Dritte keine Möglichkeit bereitstellen, objektinterne Daten zu verändern. Unsere Beispielklasse Auto enthält die konstante Methode info , sie greift nur lesend auf die Membervariablen zu, um ihre Werte auszugeben. Wenn Sie ein konstantes Auto Objekt erstellen, können Sie info problemlos aufrufen.

Versuchen Sie jedoch fahren oder tanken aufzurufen, wird Ihr Compiler dies mit einer Fehlermeldung quittieren. Wie Sie an diesem Beispiel sehen, lässt sich eine Methode als konstant auszeichnen, indem nach der Parameterliste das Schlüsselwort const angegeben wird.

Diese Auszeichnung folgt also auch der einfachen Regel: Da const zum Methodenprototyp zählt, muss es natürlich auch bei der Definition der Methode angegeben werden.

Es sei noch einmal explizit darauf hingewiesen, dass sich die Konstantheit einer Methode lediglich auf die Membervariablen der zugehörigen Klasse auswirkt. Es ist problemlos möglich, eine als Parameter übergebene Variable zu modifizieren. Vielleicht haben Sie sich bereits gefragt, wofür es gut sein soll, ein Objekt als konstant auszuzeichnen, wenn der Zweck eines Objektes doch darin besteht, mit den enthaltenen Daten zu arbeiten.

Beim Erstellen eines konstanten Objektes können Sie es einmalig über den Konstruktor mit Werten belegen. In diesem Fall haben Sie von einem konstanten Objekt das gleiche, wie bei konstanten Variablen von Basisdatentypen.

Oft ist es jedoch nicht möglich, alle Einstellungen zu einem Objekt über den Konstruktoraufruf festzulegen. Der Ansatz, Klassen so zu gestalten, dass man immer alle Werte über den Konstruktor festlegen kann, hat also seine Grenzen.

In diesem Fall hat es einfach keinen Sinn, ein Objekt bei der Erstellung konstant zu machen, denn die Einstellungen werden erst nach dem Erstellen des Objektes vorgenommen. Innerhalb einer solchen Funktion wäre das Objekt also konstant. Zugriffsmethoden sollten eigentlich vermieden werden, aber manchmal sind sie nützlich. Eine Zugriffsmethode macht nichts anderes, als eine Membervariable lesend oder schreibend zugreifbar zu machen:.

Get-Methoden sind immer konstant, da sie den Wert ja nur lesend zugreifbar machen sollen. Eine Set-Methode kann dagegen nie mit einem konstanten Objekt benutzt werden. Solche Einzeiler werden normalerweise einfach direkt in die Funktionsdeklaration geschrieben, dadurch sind sie auch gleich automatisch als inline ausgezeichnet. Dazu müssen Sie nur das Semikolon durch den Funktionsrumpf ersetzen. Sollten Sie dennoch lieber eine eigene Definition für solche Methoden machen wollen, dann achten Sie darauf, diese bei der Definition als inline zu kennzeichnen.

Falls Sie mit Headerdateien arbeiten, dann beachten Sie, dass der Funktionsrumpf bei inline -Methoden während des Kompilierens bekannt sein muss. Die Definition muss also mit in die Headerdatei, nicht wie gewöhnlich in die Quelldatei. Sie haben bereits gelernt, dass Funktionen überladen werden können, indem für den gleichen Funktionsnamen mehrere Deklarationen mit verschiedenen Parametern gemacht werden.

Auch bei Klassenkonstruktoren haben Sie Überladung bereits kennengelernt. Für gewöhnliche Memberfunktionen ist eine Überladung ebenfalls nach den Ihnen bereits bekannten Kriterien möglich. Zusätzlich können Sie Memberfunktionen aber anhand des eben vorgestellten const -Modifizierers überladen.

Natürlich können auch Methoden mit Parametern auf diese Weise überladen werden. Die nicht-konstante Version wird immer dann aufgerufen, wenn Sie mit einem nicht-konstanten Objekt der Klasse arbeiten. Analog dazu wird die konstante Version aufgerufen, wenn Sie mit einem konstanten Objekt arbeiten. Wenn Sie nur eine konstante Version deklarieren, wird immer diese aufgerufen.

Sinnvoll ist diese Art der Überladung vor allem dann, wenn Sie einen Zeiger oder eine Referenz auf etwas innerhalb des Objekts zurückgeben. Wie Sie sich sicher erinnern, kann eine Überladung nicht anhand des Rückgabetyps einer Funktion oder Methode gemacht werden.

Das folgende Beispiel wird Ihnen zeigen, wie Sie eine const -Überladung nutzen können, um direkte Manipulation von Daten innerhalb eines Objekts nur für nicht-konstante Objekte zuzulassen. Im Kapitel über Operatoren überladen werden Sie noch ein Beispiel zu dieser Technik kennenlernen, welches in der Praxis oft zu sehen ist.

Im Beispiel von eben geben die beiden Funktionen lediglich eine Referenz auf eine Membervariable innerhalb des Objekts zurück. In der Regel wird eine solche Funktion natürlich noch etwas mehr tun, zum Beispiel den Zugriff protokollieren und den aktuellen Wert auf dem Bildschirm ausgeben. Dann wäre es nötig, zwei Funktionen zu schreiben, die den gleichen Code enthalten.

Das wiederum ist ausgesprochen schlechter Stil. Stellen Sie sich nur vor, Sie möchten die Funktion später aus irgendwelchen Gründen ändern, dann müssten Sie alle Änderungen an zwei Stellen im Code vornehmen. Daher ist es sinnvoll, wenn eine Variante die andere aufruft. Hierfür sind einige Tricks nötig, da Sie einer der beiden Varianten beibringen müssen, eine Methode aufzurufen, die eigentlich nicht zum const -Modifizierer des aktuellen Objekts passt.

Die konstante Variante verspricht, niemals eine Änderung am Objekt vorzunehmen, sie ist in ihren Möglichkeiten also stärker eingeschränkt. Die nicht konstante Version darf hingegen alles, was auch die konstante Version darf. Somit ist es sinnvoll, die konstante Version von der nicht-konstanten aufrufen zu lassen; so kann die Methode, die mehr darf, später erweitert werden um Aktivitäten, die nur sie darf, ohne die Aufrufstruktur umstellen zu müssen.

Um nun der nicht-konstanten Version beizubringen, dass sie ihr konstantes Äquivalent aufrufen soll, müssen wir zunächst einmal aus dem aktuellen Objekt ein konstantes Objekt machen.

Jede Klasse enthält eine spezielle Variable, den sogenannten this -Zeiger, der innerhalb einer Membervariable einen Zeiger auf das aktuelle Objekt repräsentiert. Diesen this -Zeiger casten wir in einen Zeiger auf ein konstantes Objekt. Nun haben wir einen Zeiger auf das Objekt, über den wir nur konstante Methoden aufrufen können. Das Problem ist nun, dass die aufgerufene Methode natürlich auch eine Referenz auf eine konstante Variable aufruft.

Da wir ja wissen, dass das aktuelle Objekt eigentlich gar nicht konstant ist, können wir die Konstantheit für die zurückgegebene Referenz guten Gewissens entfernen. Beachten Sie jedoch, dass dieser Cast wirklich nur auf Variablen angewendet werden darf, die eigentlich nicht konstant sind! Wie schon gesagt, sieht diese Technik in unserem Beispiel überdimensioniert aus. Aber auch an dieser Stelle möchte ich Sie auf das Beispiel im Kapitel zur Operatorüberladung verweisen, wo sie, aufgrund der umfangreicheren konstanten Version, bereits deutlich angenehmer erscheint.

Ihr Compiler wird die casting-Operationen vermutlich wegoptimieren. Im Gegensatz zu den vorangegangenen Kapiteln dieses Abschnitts geht es diesmal nicht darum, wie man Objekte aufbaut, sondern wie man mit ihnen arbeitet.

Wie dort bereits erwähnt, ist es für Klassenobjekte effizienter, sie als Referenz an eine Funktion zu übergeben. Bei der Übergabe einer Variablen als Wert muss von dieser Variable erst eine Kopie angefertigt werden.

Zusätzlich führt der Kopierkonstruktor an dieser Stelle möglicherweise noch irgendwelche zusätzlichen Operationen aus, die Zeit kosten. Bei einer Übergabe als Referenz muss hingegen nur die Speicheradresse des Objekts kopiert werden. Wenn wir dann noch dafür sorgen, dass die Referenz auf ein konstantes Objekt verweist, haben wir eine fast kostenlose Übergabe und gleichzeitig die Sicherheit, dass die übergebene Variable innerhalb der Funktion nicht verändert wird.

Die Methode von B kann auf die 4 Variablen von A lesend zugreifen, sie aber nicht verändern. Die Übergabe als Wert ist dann sinnvoll, wenn innerhalb einer Methode ohnehin eine Kopie der Variablen benötigt wird.

Nun können auf das A-Objekt beliebige lesende oder schreibende Operationen angewendet werden. Da sie auf einer Kopie ausgeführt werden, bleibt auch hier das Originalobjekt unverändert, aber eben zu dem Preis, dass zusätzlich Zeit und Speicherplatz benötigt werden, um eine Kopie des Objekts zu erstellen.

In den meisten Fällen ist es nicht nötig, innerhalb einer Methode Schreiboperationen auszuführen.