Bedeutung von ‘const’ in einer functionsdeklaration einer class?

Was bedeutet const in solchen Deklarationen? Die const verwirrt mich.

 class foobar { public: operator int () const; const char* foo() const; }; 

   

Wenn Sie einer Methode das Schlüsselwort const hinzufügen, wird der this pointers im Wesentlichen zu einem pointers auf const Objekt und Sie können daher keine Mitgliedsdaten ändern. (Es sei denn, Sie verwenden mutable , mehr dazu später).

Das Schlüsselwort const ist Teil der functionssignatur, was bedeutet, dass Sie zwei ähnliche Methoden implementieren können, eine Methode, die aufgerufen wird, wenn das Objekt const , und eine const , die nicht aufgerufen wird.

 #include  class MyClass { private: int counter; public: void Foo() { std::cout < < "Foo" << std::endl; } void Foo() const { std::cout << "Foo const" << std::endl; } }; int main() { MyClass cc; const MyClass& ccc = cc; cc.Foo(); ccc.Foo(); } 

Dies wird ausgegeben

 Foo Foo const 

In der non-const-Methode können Sie die Instanzmitglieder ändern, was in der const Version nicht möglich ist. Wenn Sie die Methodendeklaration im obigen Beispiel in den folgenden Code ändern, erhalten Sie einige Fehler.

  void Foo() { counter++; //this works std::cout < < "Foo" << std::endl; } void Foo() const { counter++; //this will not compile std::cout << "Foo const" << std::endl; } 

Dies ist nicht vollständig richtig, da Sie ein mutable als mutable markieren können und eine const Methode es dann ändern kann. Es wird hauptsächlich für interne Zähler und so verwendet. Die Lösung dafür wäre der folgende Code.

 #include  class MyClass { private: mutable int counter; public: MyClass() : counter(0) {} void Foo() { counter++; std::cout < < "Foo" << std::endl; } void Foo() const { counter++; std::cout << "Foo const" << std::endl; } int GetInvocations() const { return counter; } }; int main(void) { MyClass cc; const MyClass& ccc = cc; cc.Foo(); ccc.Foo(); std::cout << "The MyClass instance has been invoked " << ccc.GetInvocations() << " times" << endl; } 

was würde ausgeben

 Foo Foo const The MyClass instance has been invoked 2 times 

Die Konstante bedeutet, dass die Methode verspricht, keine Mitglieder der class zu verändern. Sie könnten die so markierten Objekte des Objekts ausführen, selbst wenn das Objekt selbst als const markiert wäre:

 const foobar fb; fb.foo(); 

wäre legal.

Siehe Wie viele und welche sind die Verwendungen von “const” in C ++? für mehr Informationen.

Das const Qualifikationsmerkmal bedeutet, dass die Methoden für jeden Wert von foobar aufgerufen werden können. Der Unterschied entsteht, wenn Sie eine nichtkonstante Methode für ein konstantes Objekt aufrufen. Überlegen Sie, ob Ihr foobar Typ die folgende zusätzliche Methodendeklaration hatte:

 class foobar { ... const char* bar(); } 

Die Methode bar() ist nicht const und kann nur von nicht konstanten Werten aus aufgerufen werden.

 void func1(const foobar& fb1, foobar& fb2) { const char* v1 = fb1.bar(); // won't compile const char* v2 = fb2.bar(); // works } 

Die Idee hinter const besteht darin, Methoden zu markieren, die den internen Zustand der class nicht verändern. Dies ist ein mächtiges Konzept, aber in C ++ nicht durchsetzbar. Es ist mehr ein Versprechen als eine Garantie. Und eine, die oft kaputt und leicht kaputt ist.

 foobar& fbNonConst = const_cast(fb1); 

Diese Konstanten bedeuten, dass der Compiler einen Fehler hat, wenn die Methode ‘with const’ interne Daten ändert.

 class A { public: A():member_() { } int hashGetter() const { state_ = 1; return member_; } int goodGetter() const { return member_; } int getter() const { //member_ = 2; // error return member_; } int badGetter() { return member_; } private: mutable int state_; int member_; }; 

Der Test

 int main() { const A a1; a1.badGetter(); // doesn't work a1.goodGetter(); // works a1.hashGetter(); // works A a2; a2.badGetter(); // works a2.goodGetter(); // works a2.hashGetter(); // works } 

Lesen Sie dies für weitere Informationen

Blairs Antwort ist auf dem Papier.

Beachten Sie jedoch, dass es ein mutable Qualifikationsmerkmal gibt, das zu den Datenelementen einer class hinzugefügt werden kann. Jedes so markierte Element kann in einer const Methode geändert werden, ohne den const Vertrag zu verletzen.

Sie können dies beispielsweise verwenden, wenn Sie möchten, dass ein Objekt sich daran erinnert, wie oft eine bestimmte Methode aufgerufen wurde, ohne die “logische” Konsistenz dieser Methode zu beeinflussen.

Bedeutung einer Const-Member-function in C ++ Allgemeinwissen: Die essentielle Intermediate-Programmierung gibt eine klare Erklärung:

Der Typ des this-pointerss in einer nichtkonstanten Elementfunktion einer class X ist X * const. Das heißt, es ist ein konstanter pointers auf ein nicht-konstantes X (siehe Const Pointer und Pointer zu Const [7, 21]). Da das Objekt, auf das es sich bezieht, nicht const ist, kann es geändert werden. Der Typ davon in einer Konst-Member-function einer class X ist const X * const. Das heißt, es ist ein konstanter pointers auf eine Konstante X. Da das Objekt, auf das sich dieses bezieht, const ist, kann es nicht geändert werden. Das ist der Unterschied zwischen den functionen const und non-const.

Also in deinem Code:

 class foobar { public: operator int () const; const char* foo() const; }; 

Du kannst es so denken:

 class foobar { public: operator int (const foobar * const this) const; const char* foo(const foobar * const this) const; }; 

Wenn Sie const in der Methodensignatur verwenden (wie Sie sagten: const char* foo() const; ), sagen Sie dem Compiler, dass der Speicher, auf den er verweist, nicht durch diese Methode geändert werden kann (was foo hier ist).