namespace cpp {}

C++ lernen, kennen, anwenden

Benutzer-Werkzeuge

Webseiten-Werkzeuge


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 ''DATA''-Anweisung ist es, Namen für Konstanten festzulegen; anstatt an jeder Stelle im Programm, wo π vorkommt, ''3.141592653589793'' zu schreiben, kann man diesen Wert mit einer ''DATA''-Anweisung einer Variablen ''PI'' zuweisen und diese dann anstelle der Langform verwenden. Dies vereinfacht auch die Änderung des Programms, falls sich der Wert von π ändern sollte.
 +>>---    FORTRAN Manual der Firma Xerox
 +
 +>    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.
 +>>---    Bruce Eckel
 +
 +>    It's hard at first, but using const really tightens up your coding style.
 +>    Const correctness grows on you.
 +>>---    Todd Hoff
 +
 +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 
 +''const'' in C++ in prozeduralen und objekt-orientierten Programmen.
 +
 +===== 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 ''const'' wurde 1983 in C++ und 1984 
 +in den Standard der Vorgängersprache C übernommen [D&E]. 
 +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);
 +</code>
 +(siehe obiges Xerox-Zitat [PI]). 
 +Solche globalen "magischen" Zahlen im Quelltext zu suchen und zu übersehen, 
 +ist ein Alptraum jedes Wartungsprogrammierers. 
 +C-Makrokonstanten in C++ zu verwenden ist zwar möglich, 
 +aber es gibt Bestrebungen, dies künftig zu ächten:
 +
 +<code cpp>
 +#define ARRAYSIZE 10
 +#define PI (4.0*atan(1.0))    /* wird jedes Mal neu berechnet ! */
 +</code>
 +
 +Dankbare Abnehmer für Konstanten sind Felder:
 +<code cpp>
 +  float array[ARRAYSIZE];
 +
 +  std::cout << "Eingabe von " << ARRAYSIZE << " Werten:\n";
 +  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 << "Partialsumme " << (i+1) << " = " << array[i] << '\n';
 +  }
 +</code>
 +
 +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, wenn sich der Wert ''ARRAYSIZE'' 
 +zwischendurch auch, natürlich unabsichtlich, ändern kann?
 +
 +==== 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
 +</code>
 +
 +Der direkte Änderungsversuch erzeugt einen Übersetzungsfehler. 
 +C-Programmierer sagen trotzdem zur ''const''-Variablen ungern Konstante, weil sie
 +
 +  *  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 ''const'' zu umgehen ist. 
 +Die kriminelle Energie, das herauszufinden, muss schon jeder selbst aufbringen.)
 +
 +Aber ist das nicht ein Widerspruch in sich: konstante Variable? 
 +Das Schlüsselwort ''const'' meint, das der Programmierer den Wert nicht ändern will. 
 +Sehr wohl kann sich der Wert einer ''const''-Variable aber aus Gründen ändern, 
 +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)
 +</code>
 +
 +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 !!
 +</code>
 +
 +Aus diesem Grund wurden extra für C++ die Referenzen erfunden, 
 +die es ermöglichen, (verdeckt) nur die Adresse einer Variable zu übergeben:
 +
 +<code cpp>
 +void ausgabe2(Vec3& v);  // nur 4 Byte Adresse
 +</code>
 +
 +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) ?
 +</code>
 +
 +den Wert von ''v'' ändert, 
 +müsste man den Quelltext von ''ausgabe2()'' kontrollieren, und zwar jedesmal, 
 +wenn man wieder neu übersetzt; 
 +schließlich könnte einer inzwischen den Code von ''ausgabe2()'' geändert haben. 
 +Dies ist nicht praktikabel, abgesehen davon, 
 +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
 +</code>
 +
 +Der Implementierer von ''ausgabe3()'' gibt bekannt, dass er ''v'' nicht ändern will. 
 +Eine Analogie zur Dateiorganisation des Betriebssystems 
 +ist an der Stelle vielleicht nützlich: 
 +''const'' wirkt wie das Schreibschutzattribut (oder entzogenes Schreibrecht) 
 +für den Nutzer der ''const''-Variablen. 
 +Referenzen entsprechen Verküpfungen (oder soft links) auf anderswo stehende Daten.
 +
 +Ändert der Implementierer das konstante ''v'' unabsichtlich, 
 +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 ''v'' beim Aufruf im Nur-Lese-Bereich des Programmspeichers, 
 +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
 +</code>
 +
 +Eine einfachere Frage: 
 +Was ist (vom Namen abgesehen) der Unterschied der nächsten Zeilen?
 +
 +<code cpp>
 +  char s1[] = "Hallo";
 +  char *s2  = "Ballo";
 +</code>
 +
 +Antwort: Der Zeiger ''s2'' darf versetzt werden, der Feldname ''s1'' dagegen nicht.
 +
 +<code cpp>
 +  s2 = s1; // erlaubt
 +  s1 = s2; // Fehler! Ein Feld kann nicht umziehen!
 +</code>
 +
 +Feldnamen können wie unveränderliche Zeiger betrachtet werden 
 +(obwohl sie es genau genommen auch nicht sind). 
 +Die Anfangswertbelegung von ''s2'' ist darüber hinaus auch noch gefährlich:
 +
 +<code cpp>
 +  s2[1] = 'e';
 +</code>
 +
 +führt zu einem Programmabsturz (segmentation fault) unter Unix, 
 +sofern ''s2'' auf die Zeichenkette "Ballo" im Nur-Lese-Programmspeicherbereich zeigt. 
 +Der Inhalt von "Hallo" dagegen darf geändert werden.
 +
 +Mit diesen Vor-Überlegungen kommen wir der Antwort auf die schwierige Frage näher. 
 +Das Schlüsselwort ''const'' kann in (für Anfänger verwirrender) Kombination 
 +mit Zeigern sogar mehrfach auftauchen:
 +
 +<code cpp>
 +        char *s3 = "schlecht";   // strcpy(s3, "peng"); => core dump!
 +  const char *s4 = "sicher";      
 +  char* const s5 = s1;           // zeigt immer auf den Feldanfang von s1 
 +  const char* const s6 = "ewig";
 +</code>
 +
 +Zum Verstehen hilft, die Definition "von innen nach außen" zu lesen, 
 +d.h. vom definierten Namen ausgehend:
 +
 +  s6            const      *         char     const
 +  s6 ist ein konstanter Zeiger auf Zeichen-Konstanten
 +
 +mit dem unveränderlichen Inhalt "ewig"
 +Durch das näherstehende ''const'' ist der Zeiger ''s6'' eingefroren. 
 +Er darf weder woanders hinzeigen noch wandern, nicht mal wackeln. 
 +Das weiter entfernte ''const'' verbietet außerdem die Änderung des Zeichenketteninhaltes.
 +
 +Die Konstant-Deklaration hat Folgen, 
 +die den Umgang zunächst erschweren und dazu verführen, 
 +''const'' generell wegzulassen. Der Compiler weigert sich bei dieser Anweisung:
 +
 +<code cpp>
 +  char* s7 = s4; // Fehler: kann const char* nicht in char* umwandeln
 +</code>
 +
 +Aus gutem Grund, denn nachfolgend könnte mit
 +
 +<code cpp>
 +  s7[0] = 'k';
 +</code>
 +
 +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 
 +''const'' weiter zu, 
 +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 
 +''const'' leicht unter die Räder. 
 +Aus Fehlern lernt man (hoffentlich, falls überhaupt). 
 +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], int anfangseinzahlung);
 +  char* inhaber() { return name;  }
 +  int  guthaben() { return saldo; }
 +  // ...
 +private:
 +  int  saldo;
 +  char name[40]; 
 +};
 +
 +Konto vielGeld("du", 10000);
 +</code>
 +
 +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(), "ich");
 +  std::cout << vielGeld.inhaber() << '\n'; // Jetzt ist es meins!
 +</code>
 +
 +In der Klasse steht eine Hintertür offen. 
 +Die Methode ''inhaber()'' liefert einen Zeiger 
 +als Haken oder Diederich ins Innere ihres Geldtresors, der alles ändern darf. 
 +Ohne Fehlermeldung, ohne Hindernis. 
 +Fünf unscheinbare Buchstaben am Ergebnistyp hätten uns aufgehalten:
 +
 +<code cpp>
 +class Konto
 +{
 +public:
 +  char const* inhaber() { return name; }
 +  // ...
 +};
 + 
 + // ...
 + strcpy(vielGeld.inhaber(), "ich"); // Fehler! 
 +</code>
 +
 +indem der Compiler beklagt, dass der von ''inhaber()'' gelieferte 
 +''const char*'' nicht in ''char*'' umwandelbar ist, 
 +wie ''strcpy(ziel, quelle)'' das von der Zielzeichenkette erwartet.
 +
 +==== 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], int anfangseinzahlung)
 +  std::string inhaber() { return name; }
 +  // ...
 +private:
 +  std::string const name; 
 +  // ...
 +};
 +</code>
 +
 +Dann ist ein ''std::string'' besser geeignet, denn wie sollte der Name 
 +mit ''strcpy()'' in ein konstantes ''char''-Feld geschrieben werden? 
 +(Es geht, aber erfordert ''const''-Betrügereien.) 
 +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::Konto(char const inhabername[40], int anfangseinzahlung)
 +: name(inhabername, 39), saldo(anfangseinzahlung)
 +{
 +}
 +</code>
 +
 +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 ''const'' vereinbart. 
 +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 ''strcpy()'' 
 +die Reihenfolge der Parameter zu verwechseln:
 +
 +<code cpp>
 +Konto::Konto(char inhabername[40], int anfangseinzahlung)
 +{
 +  strcpy( inhabername, name ); // Peng!
 +  saldo = anfangseinzahlung;
 +}
 +</code>
 +
 +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 ''const'' lässt den Compiler sofort beim Übersetzen Krach schlagen. 
 +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()
 +            << "Guthaben in Taler: " << konto.guthaben() << '\n';
 +  /*
 +  int falschgeld = konto.abheben( konto.guthaben() );
 +  std::cout << "Wir geben gleich aus soviel " << falschgeld << '\n';
 +  */
 +}
 +</code>
 +
 +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& konto)
 +{
 +  std::cout << "Name des Inhabers: " << konto.inhaber()
 +            << "Guthaben in Taler: " << konto.guthaben() << '\n';
 +  /*
 +  int echtesgeld = konto.abheben( konto.guthaben() );
 +  std::cout << "Wir geben gleich aus soviel " << echtesgeld << '\n';
 +  */
 +}
 +</code>
 +
 +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)
 +{
 +   std::cout << "Name des Inhabers: " << konto.inhaber()
 +             << "Guthaben in Taler: " << konto.guthaben() << '\n';
 +}
 +</code>
 +
 +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 ''getInhaber()'' und ''getGuthaben()'' umbenannt werden.
 +
 +Beim Klassenentwurf legen Sie fest, was welche Methode tun soll: 
 +''einzahlen(betrag)'' und ''abheben(betrag)'' werden den Saldo vermutlich ändern wollen. 
 +Methoden mit ''get...()'', ''hat..()'', ''has...()'', ''ist...()'' oder 
 +''is...()'' im Namen (deutsch, englisch, oder grauenhaft dänglisch) 
 +fragen nur Werte ab oder berechnen diese. 
 +Für ändernde (schreibende) Methoden wählen manche Designer gern Namen wie 
 +''set...()'', ''setze...()'' usw.
 +
 +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 ''const''
 +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 ''<iostream>''-Bibliothek, Jerry Schwarz, 
 +hat sich nicht an ''set...()'' und ''get...()'' gehalten. Es ist klar, 
 +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::cout.precision();  
 +  std::cout.precision(10);              // Wir wollen's genauer als 6 Ziffern!
 +</code>
 +
 +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?) geschrieben steht, 
 +welche Rolle die Methode spielt.
 +
 +Kritiker finden, die Lesbarkeit sei herabgesetzt, 
 +da ''istFormale szsetVorsilben'' den ''szgetTextfluss istEmpfindlich setStören''
 +''istStimmt''s? 
 +Der dauernde Groß-/klein-Wechsel erschwert Lesen und Schreiben gleichermaßen. 
 +''Sehr_lange_zusammengesetzte_Bezeichner'' können besser mit Unterstrichen verkoppelt werden. 
 +Zudem können Bezeichner auch lügen. Vielleicht muss eine Methode sich 
 +im Verlaufe ihrer Entwicklung Schreibzugriffen öffnen oder verschließen. 
 +Wird dann ''get...()'' / ''set...()'' überall geändert? 
 +Es ist zu befürchten, nein. 
 +Schließlich findet Software-Entwicklung fast immer unter Zeitdruck statt.
 +
 +Wer garantiert dann die Korrektheit? Dies ist eine Aufgabe, 
 +die nicht fehlerbehafteten und allzu toleranzwilligen menschlichen Wesen überlassen bleiben kann. 
 +Zumal es zuverlässige Werkzeuge gibt, die ''const''-Korrektheit überwachen. Compiler.
 +
 +Woher soll aber der Compiler "wissen", dass die Funktion ''guthaben()'' 
 +oder ''getGuthaben()'' nicht ihr Guthaben verändert? 
 +Sie müssen es ihm verständlich machen. 
 +Mit den Schlüsselwort ''const'' an der richtigen Stelle. 
 +Studieren Sie z.B. auch die Definitionen der ''<iostream>''-Klassen. 
 +Finden sie das ''const'':
 +
 +<code cpp>
 +class Konto
 +{
 +public:
 +  std::string inhaber() const { return name;  }
 +  int        guthaben() const { return saldo; }
 +  //...
 +};
 +</code>
 +
 +Das hinter der schließenden runden Klammer stehende Schlüsselwort gehört, 
 +genau wie die Typen der Parameterliste mit zum Funktionsnamen. 
 +Wird die ''const''-Methode außerhalb der Klassenschnittstelle implementiert, 
 +muss das ''const'' wieder mit aufgeführt werden:
 +
 +<code cpp>
 +int Konto::guthaben() const 
 +{
 +  return saldo; 
 +}
 +</code>
 +
 +Wird es vergessen, entstehen ein Compilerfehler 
 +(implementierte Funktion ''guthaben()'' ohne ''const'' 
 +in der Klassenschnittstelle Konto nicht aufgeführt) und ein Linkerfehler 
 +(Methode ''guthaben() const'' nicht implementiert). 
 +Es ist möglich, dass es zwei Methoden gibt, 
 +die sich nur im nachgestellten ''const'' unterscheiden. 
 +Ein wichtiges Beispiel ist der Indexoperator ''operator[]''.
 +
 +==== Konstanter Zustand ====
 +
 +Die ''const''-Markierung von Methoden versichert den Nutzer nach außen, 
 +dass die Methoden nichts am Inhalt des Objektes ändern. 
 +Bei konstanten Objekten können nur solche ''const''-Methoden aufgerufen werden.
 +
 +Der andere Aspekt ist aber genauso wichtig: 
 +Was nach außen versichert wird, muss nach innen garantiert und kontrolliert werden. 
 +Durch ''const'' markierte Methoden dürfen keinen Attributwert des Objektes ändern, 
 +zu dem sie gehören. Zudem dürfen aus ''const''-Methoden heraus nur 
 +ebensolche als ''const'' deklarierte Methoden aufgerufen werden, 
 +die den Zustand des Objektes nicht ändern, damit die Konstantheit gewahrt bleibt. 
 +Setzt man ''const'' ein, sind manche Verirrungen wie die folgende schnell entdeckt. 
 +Sie stammt (etwas abgewandelt und zugespitzt) 
 +aus Prüfungsarbeiten angehender Programmierer:
 +
 +<code cpp>
 +double Ware::getBruttopreis()
 +{
 +  return netto += netto*mehrwertsteuersatz/100.0;
 +}
 +</code>
 +
 +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::getBruttopreis() const
 +{
 +  return netto + netto*mehrwertsteuersatz/100.0;
 +}
 +</code>
 +
 +Das Erhöhen des Nettopreises mit ''+='' wird in einer ''const''-Methode 
 +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 ''const'' 
 +ein ganzes Buchkapitel gewidmet hat. Sie sollten es lesen. Es ist es wert.
 +
 +===== Quellen =====
 +
 +  * [PI] Jörg Arndt, Christoph Haenel: Pi. Algorithmen, Computer, Arithmetik. Springer (1998) S. 109. 
 +  * [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://www.possibility.com/Cpp/ 
 +  * [FAQ] Marshall Cline: C++ FAQ Lite. http://www.parashift.com/c++-faq-lite/const-correctness.html 
 +  * [Loder] Chad Loder: Const Correctness. C-Scene Issue #2. http://www.elitecoders.de/mags/cscene/CS2/CS2-01.html 
 +
 +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

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki