Lektion 71:Das const-SpielBisher haben wir das Wort 'const' nur verwendet, um Konstanten zu definieren und um Objekte über const-Referenzen zu übergeben. Objekte, die als const-Referenz übergeben wurden, werden vom Compiler wie Konstanten betrachtet. Das heißt ganz offensichtlich, daß Zuweisungen an diese Objekte nicht möglich sind. Es heißt aber auch, daß auf diesen Objekten keine Methode aufgerufen werden darf, die das Objekt verändern könnte. In der Klasse DictionaryEntryComparator in der Methode
wird der Fehler ==> 'getKey' : cannot convert 'this' pointer from 'const class DictionaryEntry' to 'class Dictionary' gemeldet. Auf die const-Referenz a wird nämlich eine Methode (nämlich getKey) aufgerufen, von welcher der Compiler nicht weiß, ob sie das Objekt a verändern wird. Weil das Verändern von const-Objekten aber nicht erlaubt ist, kann der Compiler den Aufruf einer Methode, die solch ein Objekt möglicherweise verändert, nicht zulassen. Wir wissen natürlich, daß getKey keine Objekte verändert. Es muß also nur noch dem Compiler erzählt werden. Und das geht, indem in der Klasse DictionaryEntry statt der Zeile
die Zeile
geschrieben wird. Ab jetzt weiß der Compiler, daß die Methode getKey ihr Objekt nicht verändert. Eine solche Methode nennt man const-Methode. Ein ähnlicher Fehler passiert jetzt in der Klasse Dictionary in der Methode
==> error: 'return' : cannot convert from 'const class DictionaryEntry' to 'class DictionaryEntry &' Conversion loses qualifiers Der Rückgabewert von m_data[index] ist eine const-Referenz. Es wird aber versucht, diese const-Referenz als normale Referenz aus dieser Methode zurückzugeben. Das darf natürlich nicht sein. Aus m_data[index] wird ja absichtlich eine const-Referenz zurückgeliefert, damit keiner den Wert verändern kann. Würde das jemand können, dann könnte er die Sortierung in der Klasse SortedArray zerstören. Und nachdem dieses Objekt erst einmal als const erklärt wurde, darf das niemand mehr aufheben, sonst könnte man das Objekt doch verändern. Es bleibt also nichts anderes übrig, als sich daran zu halten, und ebenfalls nur eine const-Referenz zurückzugeben.
Der nächste Fehler dieser Art steht in der main-Funktion in der Zeile
Der Wert von d[i] ist jetzt eine const-Referenz geworden, aber getKey ist keine const-Methode. Dieser Fehler wegen const ist also nur aufgetaucht, weil ein anderer Fehler wegen const behoben wurde. Das ist ein ganz typisches Verhalten. Deshalb habe ich diese Beschäftigung das "const-Spiel" genannt. Oft verzichtet man nämlich nachlässigerweise darauf, sich für jede Methode zu überlegen, ob dies eine const-Methode sein sollte oder nicht, und schreibt sie einfach als nicht-const-Methode. Das ist eigentlich nicht weiter schlimm. Doch irgendwann wird der Compiler bei der Verwendung einer const-Referenz mißtrauisch werden und einen entsprechenden Fehler melden. Der muß behoben werden, indem eine Methode const gemacht wird. Das hat dann weitere Veränderungen zur Folge, die alle mit const zu tun haben. Mitunter kann man sich damit eine halbe Stunde beschäftigen, bis endlich alle Fehler beseitigt sind. Zum Glück sind die Spielregeln recht einfach, und mit ein bißchen Überlegung gewinnen Sie immer. Im vorliegenden Fall muß getKey zu einer const-Methode gemacht werden.
Für getValue gilt entsprechendes.
Jetzt meldet der Compiler in dieser Methode ==> 'return' : cannot convert from 'const int' to 'int &' Conversion loses qualifiers Beachten Sie, daß die Ersetzung des Typs VALUE in int sich sogar in den Fehlermeldungen niederschlägt. Damit hat er wieder recht. Behoben wird es wie immer.
Allerdings liegt das nicht in unserem Interesse. Der Wert darf verändert werden, denn er beeinflußt die Sortierung nicht! Eigentlich sollte es doch möglich sein, einen Wert zu verändern, aber der Compiler läßt das nicht zu. Es gibt auch keinen einfachen Ausweg, weil bereits die verwendete Klasse SortedArray dieses const vorschreibt. Jetzt einfach dort auf das const zu verzichten, wäre keine Lösung, denn wenn jemand diese Klasse verwenden möchte, dann gäbe es dort Probleme. Der Rückgabewert des operator[] in der Klasse SortedArray muß eine const-Referenz sein, damit die Sortierung nicht zerstört werden kann. Diese Runde geht also an den Compiler. Alle Fehler sind zwar jetzt beseitigt, aber es ist dem Compiler gelungen, etwas durchzusetzen, das nicht in unserem Sinne ist. Aus diesem Dilemma kann nur ein Tiefschlag helfen. Dieser Tiefschlag heißt const_cast. Mit const_cast kann man eine Variable, die const ist, auf nicht-const zwingen.
In die Template-Klammern von const_cast schreibt man den Typ, den das Ergebnis haben soll. Die unschöne Schreibweise von const_cast ist von den Entwicklern von C++ absichtlich so gewählt worden, damit man immer wieder daran erinnert wird, daß man eigentlich dieses Mittel nicht verwenden darf. Hier in diesem Fall ist es erlaubt, weil die Klasse Dictionary der von ihr verwendeten Klasse SortedArray immer einen DictionaryComparator als Comparator mitgibt. Nur, wenn wirklich sichergestellt ist, daß const_cast nicht schaden kann, dürfen Sie es verwenden. Obwohl in diesem Fall sichergestellt ist, daß der const_cast keinen Schaden anrichten kann, bleibt ein negativer Beigeschmack. Falls Ihnen Fehler im Text auffallen oder Sie Verbesserungsvorschläge haben, dann schicken Sie mir bitte eine Mail. Ich werde mich dann sofort darum kümmern. [aktuelle Version] [inhalt] [index] [Fehlerkorrektur, Verbesserungsvorschlag] © Volkard Henkel <volkard@normannia.de>, last update: 08/25/00 |