lernen:const
no way to compare when less than two revisions
Unterschiede
Hier werden die Unterschiede zwischen zwei Versionen angezeigt.
— | lernen:const [2020-07-27 09:28] (aktuell) – angelegt - Externe Bearbeitung 127.0.0.1 | ||
---|---|---|---|
Zeile 1: | Zeile 1: | ||
+ | ====== Political const correctness ====== | ||
+ | |||
+ | > Der Hauptzweck der '' | ||
+ | >> | ||
+ | |||
+ | > All this provides a significant additional form of type checking and safety in your programming. The use of so-called const correctness (the use of const anywhere you possibly can) can be a lifesaver for projects. Although you can ignore const and continue to use old C coding practices, it's there to help you. | ||
+ | >> | ||
+ | |||
+ | > It's hard at first, but using const really tightens up your coding style. | ||
+ | > Const correctness grows on you. | ||
+ | >> | ||
+ | |||
+ | Die Konstant-Deklaration ist von politischer Tragweite. | ||
+ | Ihr korrekter Einsatz hilft, | ||
+ | saubere Entwürfe zu gestalten und ihre Datenintegrität zu sichern. | ||
+ | Dieser Artikel erörtert das Warum und Wie für den Einsatz des Schlüsselwortes | ||
+ | '' | ||
+ | |||
+ | ===== Ode an ein Schlüsselwort ===== | ||
+ | |||
+ | In Abwandlung eines Songs von Joan Baez: | ||
+ | const is just a five letter word. | ||
+ | | ||
+ | Na und? Mir geht es mit dem Wort wie einem Alkoholiker mit dem Suchtmittel: | ||
+ | ich habe kein Problem damit, sondern ohne. Ich will zu erklären versuchen, warum. | ||
+ | Ich hoffe, nachher geht es Ihnen wie mir. | ||
+ | Seien Sie nicht konstant, verändern Sie sich! | ||
+ | Es wird künftigen Quelltexten gut tun. | ||
+ | |||
+ | ==== C lernt von C++ ==== | ||
+ | |||
+ | Nein, Sie haben sich nicht verlesen. | ||
+ | Das Schlüsselwort '' | ||
+ | in den Standard der Vorgängersprache C übernommen [D& | ||
+ | Eingeführt wurde es, um unabsichtliche Änderungen von Werten zu erschweren. | ||
+ | Des Öfteren kommen Zahlen im Quelltext vor, | ||
+ | die man besser an einer Stelle definiert, | ||
+ | weil sie im Programm zwar als unveränderlich betrachtet werden, | ||
+ | aber sich von Version zu Version auch mal ändern können: | ||
+ | |||
+ | <code cpp> | ||
+ | int const ARRAYSIZE = 10; | ||
+ | double const PI = 4.0*atan(1.0); | ||
+ | </ | ||
+ | (siehe obiges Xerox-Zitat [PI]). | ||
+ | Solche globalen " | ||
+ | ist ein Alptraum jedes Wartungsprogrammierers. | ||
+ | C-Makrokonstanten in C++ zu verwenden ist zwar möglich, | ||
+ | aber es gibt Bestrebungen, | ||
+ | |||
+ | <code cpp> | ||
+ | #define ARRAYSIZE 10 | ||
+ | #define PI (4.0*atan(1.0)) | ||
+ | </ | ||
+ | |||
+ | Dankbare Abnehmer für Konstanten sind Felder: | ||
+ | <code cpp> | ||
+ | float array[ARRAYSIZE]; | ||
+ | |||
+ | std::cout << " | ||
+ | for (int i = 0; i < ARRAYSIZE; i++) | ||
+ | { | ||
+ | std::cout << "Wert " << (i+1) << " : "; | ||
+ | std::cin >> array[i]; | ||
+ | } | ||
+ | float sum = 0; | ||
+ | for (int i = 0; i < ARRAYSIZE; i++) | ||
+ | { | ||
+ | sum += array[i]; | ||
+ | array[i] = sum; | ||
+ | } | ||
+ | for (int i = 0; i < ARRAYSIZE; i++) | ||
+ | { | ||
+ | std::cout << " | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | Bisher mussten in C und müssen in C++ die Feldgrößen konstante, | ||
+ | beim Übersetzen festliegende Ausdrücke sein. Künftige C++-Standards können | ||
+ | evtl. die Festlegungen des neuen C-Sprachstandards ISO 9899:1999 übernehmen | ||
+ | und zur Laufzeit variabel festlegbare Feldgrößen erlauben | ||
+ | (wie g++ dies schon tut). | ||
+ | Was wird dann wohl mit dem Schleifenende, | ||
+ | zwischendurch auch, natürlich unabsichtlich, | ||
+ | |||
+ | ==== Konstante Variablen? ==== | ||
+ | |||
+ | Variablen sind Speicherzellen, | ||
+ | deren Wert sich durch Zuweisungen oder Operationen ändern kann. | ||
+ | Konstanten ändern sich nicht: | ||
+ | |||
+ | <code cpp> | ||
+ | int n = 10; // Variablendefinition | ||
+ | int const SIZE = 10; // const Variable | ||
+ | </ | ||
+ | |||
+ | Der direkte Änderungsversuch erzeugt einen Übersetzungsfehler. | ||
+ | C-Programmierer sagen trotzdem zur '' | ||
+ | |||
+ | * wissen, wie man const umgehen kann, | ||
+ | * der Drang, das zu tun, beliebig groß werden kann und | ||
+ | * die Bezeichnung Konstante aus historischen Gründen vom Präprozessor belegt ist. | ||
+ | |||
+ | (Ich werde schlechten Stil an dieser Stelle nicht unterstützen und nicht verraten, | ||
+ | wie '' | ||
+ | Die kriminelle Energie, das herauszufinden, | ||
+ | |||
+ | Aber ist das nicht ein Widerspruch in sich: konstante Variable? | ||
+ | Das Schlüsselwort '' | ||
+ | Sehr wohl kann sich der Wert einer '' | ||
+ | die der Programmierer nicht beeinflussen kann, | ||
+ | z.B. wenn die am seriellen Port angeschlossene Maus bewegt wird: | ||
+ | <code cpp> | ||
+ | char const volatile* COM1port = 0x000003f8; // serial in port (DOS) | ||
+ | </ | ||
+ | |||
+ | Der Port wird als flatterhaft (flüchtig = volatil) gekennzeichnet, | ||
+ | damit der Compiler tatsächlich jedesmal den Inhalt abfragt. | ||
+ | Compiler sind nämlich auch faul und können manche Zugriffe wegoptimieren, | ||
+ | besonders wenn sie durch Compiler-Einstellungen (Optimierung) dazu aufgefordert werden. | ||
+ | |||
+ | ==== Konstant gute Referenzen ==== | ||
+ | |||
+ | Manche Objekte von zusammengesetzten (nutzerdefinierten) Datentypen | ||
+ | sind echte Speicherfresser. Ihre Übergabe als Wertparameter kann sehr teuer werden: | ||
+ | |||
+ | <code cpp> | ||
+ | struct Vec3 { double x, y, z; }; | ||
+ | |||
+ | void ausgabe(Vec3 v); // muss 3 x 8 = 24 Byte kopieren !! | ||
+ | </ | ||
+ | |||
+ | Aus diesem Grund wurden extra für C++ die Referenzen erfunden, | ||
+ | die es ermöglichen, | ||
+ | |||
+ | <code cpp> | ||
+ | void ausgabe2(Vec3& | ||
+ | </ | ||
+ | |||
+ | Nur haben Referenzparameter wie die (in C üblicherweise) | ||
+ | mittels Zeiger übergebenen Parameter die unangenehme Eigenschaft, | ||
+ | sich auch innerhalb der Prozedur ändern zu können. | ||
+ | Diese Änderung wirkt dann zurück ins Hauptprogramm, | ||
+ | wie in alten FORTRAN-Zeiten. Um entscheiden zu können, ob | ||
+ | |||
+ | <code cpp> | ||
+ | Vec3 v = { 1, 2, 3 }; | ||
+ | ausgabe2(v); | ||
+ | // immer noch (1,2,3) ? | ||
+ | </ | ||
+ | |||
+ | den Wert von '' | ||
+ | müsste man den Quelltext von '' | ||
+ | wenn man wieder neu übersetzt; | ||
+ | schließlich könnte einer inzwischen den Code von '' | ||
+ | Dies ist nicht praktikabel, | ||
+ | dass Quelltext von Bibliotheken dem Nutzer auch als Geschäftsgeheimnis | ||
+ | vorenthalten werden kann und wird. | ||
+ | Bei der folgenden Funktion darf der Nutzer darauf vertrauen, | ||
+ | dass der übergebene Wert nicht geändert wird: | ||
+ | |||
+ | <code cpp> | ||
+ | void ausgabe3(Vec3 const& v); // freiwillige Selbstverpflichtung | ||
+ | </ | ||
+ | |||
+ | Der Implementierer von '' | ||
+ | Eine Analogie zur Dateiorganisation des Betriebssystems | ||
+ | ist an der Stelle vielleicht nützlich: | ||
+ | '' | ||
+ | für den Nutzer der '' | ||
+ | Referenzen entsprechen Verküpfungen (oder soft links) auf anderswo stehende Daten. | ||
+ | |||
+ | Ändert der Implementierer das konstante '' | ||
+ | wird er durch eine Fehlermeldung des Compilers deutlich darauf hingewiesen. | ||
+ | Will er es absichtlich tun, | ||
+ | muss er unweigerlich kriminell werden und die zugesicherte Schnittstelle verletzen, | ||
+ | z.B. durch einen Typecast. | ||
+ | Tut er es und liegt dann '' | ||
+ | riskiert der Anwender den Abschuss des Programms durch das stets wachende Betriebssystem. | ||
+ | Dieses ---- ich meine nicht die DOSe und deren graphische Oberfläche --- | ||
+ | versteht an dieser Stelle keinerlei Spaß: | ||
+ | |||
+ | segmentation fault, core dump. | ||
+ | |||
+ | Deutsche Fensterer kennen (und lieben) die allgemeine Schutzverletzung. | ||
+ | Manchmal ist Kontrolle eben besser. (Nur: Wozu ist dann Vertrauen gut?) | ||
+ | Bei solchen Betrachtungen darf man schon mal ethischen bis religiösen Eifer zeigen: | ||
+ | Programme in einem Multi-Tasking-System müssen sich wie Menschen auch | ||
+ | an soziale Regeln halten, soll das Ganze funktionieren. | ||
+ | Und leider kann man sich nicht immer darauf verlassen. | ||
+ | Die Kontrolle ihrerseits muss bezahlt werden, mit Zeit, Geld und Resourcen. | ||
+ | |||
+ | ==== Konstanten und Zeiger ==== | ||
+ | |||
+ | Eine schwierige Frage: Was bedeuten | ||
+ | |||
+ | <code cpp> | ||
+ | char* | ||
+ | const char* | ||
+ | char* const | ||
+ | const char* const | ||
+ | </ | ||
+ | |||
+ | Eine einfachere Frage: | ||
+ | Was ist (vom Namen abgesehen) der Unterschied der nächsten Zeilen? | ||
+ | |||
+ | <code cpp> | ||
+ | char s1[] = " | ||
+ | char *s2 = " | ||
+ | </ | ||
+ | |||
+ | Antwort: Der Zeiger '' | ||
+ | |||
+ | <code cpp> | ||
+ | s2 = s1; // erlaubt | ||
+ | s1 = s2; // Fehler! Ein Feld kann nicht umziehen! | ||
+ | </ | ||
+ | |||
+ | Feldnamen können wie unveränderliche Zeiger betrachtet werden | ||
+ | (obwohl sie es genau genommen auch nicht sind). | ||
+ | Die Anfangswertbelegung von '' | ||
+ | |||
+ | <code cpp> | ||
+ | s2[1] = ' | ||
+ | </ | ||
+ | |||
+ | führt zu einem Programmabsturz (segmentation fault) unter Unix, | ||
+ | sofern '' | ||
+ | Der Inhalt von " | ||
+ | |||
+ | Mit diesen Vor-Überlegungen kommen wir der Antwort auf die schwierige Frage näher. | ||
+ | Das Schlüsselwort '' | ||
+ | mit Zeigern sogar mehrfach auftauchen: | ||
+ | |||
+ | <code cpp> | ||
+ | char *s3 = " | ||
+ | const char *s4 = " | ||
+ | char* const s5 = s1; // zeigt immer auf den Feldanfang von s1 | ||
+ | const char* const s6 = " | ||
+ | </ | ||
+ | |||
+ | Zum Verstehen hilft, die Definition "von innen nach außen" | ||
+ | d.h. vom definierten Namen ausgehend: | ||
+ | |||
+ | s6 const * | ||
+ | s6 ist ein konstanter Zeiger auf Zeichen-Konstanten | ||
+ | |||
+ | mit dem unveränderlichen Inhalt " | ||
+ | Durch das näherstehende '' | ||
+ | Er darf weder woanders hinzeigen noch wandern, nicht mal wackeln. | ||
+ | Das weiter entfernte '' | ||
+ | |||
+ | Die Konstant-Deklaration hat Folgen, | ||
+ | die den Umgang zunächst erschweren und dazu verführen, | ||
+ | '' | ||
+ | |||
+ | <code cpp> | ||
+ | char* s7 = s4; // Fehler: kann const char* nicht in char* umwandeln | ||
+ | </ | ||
+ | |||
+ | Aus gutem Grund, denn nachfolgend könnte mit | ||
+ | |||
+ | <code cpp> | ||
+ | s7[0] = ' | ||
+ | </ | ||
+ | |||
+ | sich jemand ins Fäustchen lachen und die (ersehnte) Schutzverletzung doch herbeiführen. | ||
+ | |||
+ | ===== const und OOP ===== | ||
+ | |||
+ | In der objektorientierten Programmierweise (OOP) nimmt die Bedeutung von | ||
+ | '' | ||
+ | da es hier sogar in noch mehr Zusammenhängen auftauchen kann und sollte: | ||
+ | |||
+ | * nicht veränderbare Rückgabewerte von Methoden, | ||
+ | * nicht veränderbare Datenwerte in Objekten (konstante Attribute), | ||
+ | * nicht veränderbare Objekte und | ||
+ | * Methoden, die den Zustand von Objekten nicht ändern (wollen). | ||
+ | |||
+ | Beim Erlernen einer neuen Technik macht man selten alles sogleich richtig. | ||
+ | Die objektorientierte Denkweise für sich genommen ist schon schwierig genug. | ||
+ | Die Syntax für die Klassen-Definition und für die -Implementation ist neu. | ||
+ | Dabei kommt ein Aspekt wie der korrekte Einsatz des unscheinbaren Wörtchens | ||
+ | '' | ||
+ | Aus Fehlern lernt man (hoffentlich, | ||
+ | Dazu müssen wir erstmal welche machen. | ||
+ | |||
+ | ==== Die offene Hintertür ==== | ||
+ | |||
+ | Schaffen Sie auch Ihr Geld zur Bank? | ||
+ | Eröffnen Sie ein Konto und lassen Sie Ihr mühsam Erspartes einschließen: | ||
+ | |||
+ | <code cpp> | ||
+ | class Konto | ||
+ | { | ||
+ | public: | ||
+ | Konto(char inhabername[40], | ||
+ | char* inhaber() { return name; } | ||
+ | int guthaben() { return saldo; } | ||
+ | // ... | ||
+ | private: | ||
+ | int saldo; | ||
+ | char name[40]; | ||
+ | }; | ||
+ | |||
+ | Konto vielGeld(" | ||
+ | </ | ||
+ | |||
+ | Ist Ihr Geld sicher? An den Saldo kommt niemand heran. | ||
+ | Der liegt im privaten Bereich, auch der Inhabername ist privat. Wirklich? | ||
+ | Probieren wir es: | ||
+ | |||
+ | <code cpp> | ||
+ | strcpy(vielGeld.inhaber(), | ||
+ | std::cout << vielGeld.inhaber() << ' | ||
+ | </ | ||
+ | |||
+ | In der Klasse steht eine Hintertür offen. | ||
+ | Die Methode '' | ||
+ | als Haken oder Diederich ins Innere ihres Geldtresors, | ||
+ | Ohne Fehlermeldung, | ||
+ | Fünf unscheinbare Buchstaben am Ergebnistyp hätten uns aufgehalten: | ||
+ | |||
+ | <code cpp> | ||
+ | class Konto | ||
+ | { | ||
+ | public: | ||
+ | char const* inhaber() { return name; } | ||
+ | // ... | ||
+ | }; | ||
+ | |||
+ | // ... | ||
+ | | ||
+ | </ | ||
+ | |||
+ | indem der Compiler beklagt, dass der von '' | ||
+ | '' | ||
+ | wie '' | ||
+ | |||
+ | ==== Konstante Attribute ==== | ||
+ | |||
+ | In den Geschäftsbedingungen der Bank sind Übereignungen möglicherweise | ||
+ | gar nicht vorgesehen. | ||
+ | Der Inhaber des Kontos sollte nicht wechseln dürfen, | ||
+ | vorbeugend gegen Geldwäsche und Spendenskandale. | ||
+ | Der Name des Inhabers wäre als konstant anzugeben: | ||
+ | |||
+ | <code cpp> | ||
+ | class Konto | ||
+ | { | ||
+ | public: | ||
+ | Konto(char const inhabername[40], | ||
+ | std::string inhaber() { return name; } | ||
+ | // ... | ||
+ | private: | ||
+ | std::string const name; | ||
+ | // ... | ||
+ | }; | ||
+ | </ | ||
+ | |||
+ | Dann ist ein '' | ||
+ | mit '' | ||
+ | (Es geht, aber erfordert '' | ||
+ | Konstante Attribute können nicht im Konstruktorrumpf zugewiesen werden. | ||
+ | Sie erhalten ihre Werte vor dem Betreten des Konstruktors | ||
+ | in der Initialisiererliste nach dem Doppelpunkt: | ||
+ | |||
+ | <code cpp> | ||
+ | Konto:: | ||
+ | : name(inhabername, | ||
+ | { | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | Das hindert gleichzeitig den Implementierer der Klasse daran, | ||
+ | in irgendeiner Methode (un)absichtliche Änderungen am Namen vorzunehmen. | ||
+ | |||
+ | ==== Konstante Feldparameter ==== | ||
+ | |||
+ | Der übernommene Inhabername wurde auch gleich noch als '' | ||
+ | Gewöhnen Sie sich an, Feldparameter mit Eingabedaten als konstant zu kennzeichnen! | ||
+ | Damit wird die Gefahrenquelle gestopft, | ||
+ | in der ersten Version der Konto-Klasse bei '' | ||
+ | die Reihenfolge der Parameter zu verwechseln: | ||
+ | |||
+ | <code cpp> | ||
+ | Konto:: | ||
+ | { | ||
+ | strcpy( inhabername, | ||
+ | saldo = anfangseinzahlung; | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | Ich weiß, das passiert echten Programmierern nicht. Wirklich. Niemals. | ||
+ | Nur Anfängern. Sie merken (vielleicht) beim Test zur Laufzeit, | ||
+ | dass hier etwas schiefgelaufen ist. Vielleicht stürzt das Testprogramm ab. | ||
+ | Möglicherweise wundern Sie sich nur, | ||
+ | dass das Konto im Schweizer-Banken-Stil namenlos bleibt. | ||
+ | Ungünstigstenfalls lauert der Fehler solange unentdeckt, | ||
+ | bis er entsprechend Murphys Gesetz mit maximalem Erfolg zuschlagen kann. | ||
+ | (Murphys Gesetz wurde schließlich auch nicht von Murphy entdeckt, | ||
+ | sondern von einem anderen Mann gleichen Namens.) | ||
+ | |||
+ | Das kleine Wörtchen '' | ||
+ | Es erspart stundenlange erfolglose, nervenaufreibende Fehlersuche und Debuggersitzungen. | ||
+ | |||
+ | ==== (Zeitweise) konstante Objekte ==== | ||
+ | |||
+ | Sie wollen Ihren Kontoauszug holen. | ||
+ | Sie könnten sich dazu eine Kopie des Kontos anlegen (sic!), den Auszug drucken, | ||
+ | das (farb)kopierte Geld abheben und anschließend verjubeln: | ||
+ | |||
+ | <code cpp> | ||
+ | void auszug(Konto konto) | ||
+ | { | ||
+ | std::cout << "Name des Inhabers: " << konto.inhaber() | ||
+ | << " | ||
+ | /* | ||
+ | int falschgeld = konto.abheben( konto.guthaben() ); | ||
+ | std::cout << "Wir geben gleich aus soviel " << falschgeld << ' | ||
+ | */ | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | Das originale Konto ist immer noch voll. | ||
+ | Den auskommentierten Teil habe ich nur eingefügt, um zu verdeutlichen: | ||
+ | Als Erbe von C zeigen Funktionsparameter in C++ Wertverhalten, | ||
+ | verwirklicht durch Kopien. | ||
+ | Referenzen müssen in C++ extra gekennzeichnet werden: | ||
+ | |||
+ | <code cpp> | ||
+ | void auszug(Konto& | ||
+ | { | ||
+ | std::cout << "Name des Inhabers: " << konto.inhaber() | ||
+ | << " | ||
+ | /* | ||
+ | int echtesgeld = konto.abheben( konto.guthaben() ); | ||
+ | std::cout << "Wir geben gleich aus soviel " << echtesgeld << ' | ||
+ | */ | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | Der auskommentierte Teil würde die Kunden sehr ärgerlich machen, | ||
+ | weil deren Geld dann wirklich verjubelt würde. | ||
+ | Durch Abfragen sollte Ihr Kontostand nicht niedriger werden. | ||
+ | Obwohl: Manche Kreditinstitute lassen sich das Ausdrucken noch extra bezahlen, | ||
+ | trotzdem sie schon einen Teil der Kapitalerträge aus der Verfügung | ||
+ | über Ihr Guthaben einstreichen. | ||
+ | Verbitten Sie sich solchen Unfug: | ||
+ | |||
+ | <code cpp> | ||
+ | void auszug(Konto const& konto) | ||
+ | { | ||
+ | | ||
+ | << | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | Nanu? Wieso geht das nicht? Der Compiler meint, | ||
+ | dass er von einem konstanten Konto weder den Inhaber noch das Guthaben abfragen kann. | ||
+ | Daran ändert sich auch nichts, | ||
+ | wenn die Funktionsnamen in '' | ||
+ | |||
+ | Beim Klassenentwurf legen Sie fest, was welche Methode tun soll: | ||
+ | '' | ||
+ | Methoden mit '' | ||
+ | '' | ||
+ | fragen nur Werte ab oder berechnen diese. | ||
+ | Für ändernde (schreibende) Methoden wählen manche Designer gern Namen wie | ||
+ | '' | ||
+ | |||
+ | Den C++-Compiler rühren solche Moden nicht. | ||
+ | Er muss den Quelltext nicht verstehen, nur übersetzen und dabei auf Korrektheit prüfen. | ||
+ | Dazu gehört, dass auch die Konstantheit gewahrt bleibt. | ||
+ | Notfalls dadurch, dass der Quelltext nicht übersetzt wird. | ||
+ | Spätestens hier rudern Anfänger freiwillig zurück in den Abgrund | ||
+ | und lassen alle konstanten Vorsätze fahren. | ||
+ | Hauptsache, es übersetzt und wird lauffähig. Egal wie. Vergiss '' | ||
+ | Alles für die Katz. Wirklich? | ||
+ | Lassen Sie sich nicht so ins Bockshorn jagen. Nicht aufgeben, weiterlesen. | ||
+ | |||
+ | ==== Konstante Methoden ==== | ||
+ | |||
+ | Die Unterscheidung in lesende Methoden (accessors) und | ||
+ | schreibende Methoden (mutators) ist richtig und wichtig. | ||
+ | Wie die Funktionen benannt werden, ist eine Frage des Stils, nicht der Korrektheit. | ||
+ | Der Entwickler der ''< | ||
+ | hat sich nicht an '' | ||
+ | dass die Methode ohne Parameter nur einen Wert zurückgeben (holen) kann, | ||
+ | während die gleichnamige Methode mit Parameter einen Wert übernimmt, | ||
+ | der die Einstellung ändern kann: | ||
+ | |||
+ | <code cpp> | ||
+ | int stellen = std:: | ||
+ | std:: | ||
+ | </ | ||
+ | |||
+ | Vorsilben sind in solchen Sprachen notwendig, | ||
+ | die das Überladen von Funktionsnamen nicht beherrschen. | ||
+ | Aus dieser überlieferten Erfahrung stammt wohl die Praxis mit den Vorsilben. | ||
+ | In den modernen OOP-Sprachen ist sie genauso diskussionswürdig wie die | ||
+ | (sogenannte [[ungarn|ungarische]]) Simonyi-Notation. | ||
+ | Befürworter sagen, die Vorsilben erhöhten die Lesbarkeit, | ||
+ | indem deutlich (unmissverständlich? | ||
+ | welche Rolle die Methode spielt. | ||
+ | |||
+ | Kritiker finden, die Lesbarkeit sei herabgesetzt, | ||
+ | da '' | ||
+ | '' | ||
+ | Der dauernde Groß-/ | ||
+ | '' | ||
+ | Zudem können Bezeichner auch lügen. Vielleicht muss eine Methode sich | ||
+ | im Verlaufe ihrer Entwicklung Schreibzugriffen öffnen oder verschließen. | ||
+ | Wird dann '' | ||
+ | Es ist zu befürchten, | ||
+ | Schließlich findet Software-Entwicklung fast immer unter Zeitdruck statt. | ||
+ | |||
+ | Wer garantiert dann die Korrektheit? | ||
+ | die nicht fehlerbehafteten und allzu toleranzwilligen menschlichen Wesen überlassen bleiben kann. | ||
+ | Zumal es zuverlässige Werkzeuge gibt, die '' | ||
+ | |||
+ | Woher soll aber der Compiler " | ||
+ | oder '' | ||
+ | Sie müssen es ihm verständlich machen. | ||
+ | Mit den Schlüsselwort '' | ||
+ | Studieren Sie z.B. auch die Definitionen der ''< | ||
+ | Finden sie das '' | ||
+ | |||
+ | <code cpp> | ||
+ | class Konto | ||
+ | { | ||
+ | public: | ||
+ | std::string inhaber() const { return name; } | ||
+ | int guthaben() const { return saldo; } | ||
+ | //... | ||
+ | }; | ||
+ | </ | ||
+ | |||
+ | Das hinter der schließenden runden Klammer stehende Schlüsselwort gehört, | ||
+ | genau wie die Typen der Parameterliste mit zum Funktionsnamen. | ||
+ | Wird die '' | ||
+ | muss das '' | ||
+ | |||
+ | <code cpp> | ||
+ | int Konto:: | ||
+ | { | ||
+ | return saldo; | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | Wird es vergessen, entstehen ein Compilerfehler | ||
+ | (implementierte Funktion '' | ||
+ | in der Klassenschnittstelle Konto nicht aufgeführt) und ein Linkerfehler | ||
+ | (Methode '' | ||
+ | Es ist möglich, dass es zwei Methoden gibt, | ||
+ | die sich nur im nachgestellten '' | ||
+ | Ein wichtiges Beispiel ist der Indexoperator '' | ||
+ | |||
+ | ==== Konstanter Zustand ==== | ||
+ | |||
+ | Die '' | ||
+ | dass die Methoden nichts am Inhalt des Objektes ändern. | ||
+ | Bei konstanten Objekten können nur solche '' | ||
+ | |||
+ | Der andere Aspekt ist aber genauso wichtig: | ||
+ | Was nach außen versichert wird, muss nach innen garantiert und kontrolliert werden. | ||
+ | Durch '' | ||
+ | zu dem sie gehören. Zudem dürfen aus '' | ||
+ | ebensolche als '' | ||
+ | die den Zustand des Objektes nicht ändern, damit die Konstantheit gewahrt bleibt. | ||
+ | Setzt man '' | ||
+ | Sie stammt (etwas abgewandelt und zugespitzt) | ||
+ | aus Prüfungsarbeiten angehender Programmierer: | ||
+ | |||
+ | <code cpp> | ||
+ | double Ware:: | ||
+ | { | ||
+ | return netto += netto*mehrwertsteuersatz/ | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | Sie werden Ihren Augen nicht trauen. Die Ware wird jedesmal, | ||
+ | wenn Sie aufs Preisschild schauen, um 16 Prozent teurer! | ||
+ | Bei dieser Inflation können wir den Maastricht-Kriterien ade sagen. | ||
+ | Halten Sie die Preise konstant: | ||
+ | |||
+ | <code cpp> | ||
+ | double Ware:: | ||
+ | { | ||
+ | return netto + netto*mehrwertsteuersatz/ | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | Das Erhöhen des Nettopreises mit '' | ||
+ | vom Compiler beanstandet. Da kann etwas nicht stimmen. | ||
+ | Der Fehler wird erkannt, bevor er im ausführbaren Code wirksam werden kann. | ||
+ | Lassen Sie den Compiler mit über die Qualität des Quelltextes wachen. | ||
+ | Der 21. Ratschlag von Scott Meyers [Meyers] lautet: | ||
+ | |||
+ | > Use const whenever possible. | ||
+ | |||
+ | Leider ist es mir nicht gelungen, mich kurz zu fassen. | ||
+ | Ich war schon in der Schule wegen langer Aufsätze gefürchtet. | ||
+ | Ich tröste mich (und hoffentlich Sie auch) mit dem Hinweis, | ||
+ | dass Bruce Eckel [Eckel] dem Schlüsselwort '' | ||
+ | ein ganzes Buchkapitel gewidmet hat. Sie sollten es lesen. Es ist es wert. | ||
+ | |||
+ | ===== Quellen ===== | ||
+ | |||
+ | * [PI] Jörg Arndt, Christoph Haenel: Pi. Algorithmen, | ||
+ | * [D&E] Bjarne Stroustrup: Design und Entwicklung von C++. Addison-Wesley (1994) S. 112. | ||
+ | * [Meyers] Scott Meyers: Effective C++. 50 ways to improve your programs. Addison-Wesley (1992). | ||
+ | * [Eckel] Bruce Eckel: Thinking in C++. 2nd edn. Prentice-Hall (2000). | ||
+ | * [Hoff] Todd Hoff: C++ Coding standards. http:// | ||
+ | * [FAQ] Marshall Cline: C++ FAQ Lite. http:// | ||
+ | * [Loder] Chad Loder: Const Correctness. C-Scene Issue #2. http:// | ||
+ | |||
+ | Weiterführende Literatur: | ||
+ | |||
+ | * [Stroustrup] Bjarne Stroustrup: Die C++ Programmiersprache. 3. Aufl. Addison-Wesley (1998) S.102-105. | ||
+ | |||
lernen/const.txt · Zuletzt geändert: 2020-07-27 09:28 von 127.0.0.1