2014-09-22 8 views
9

Ich möchte eine Frage über die Const-Korrektheit von Methoden stellen. Lassen Sie mich die Situation veranschaulichen.Ist es eine gute Übung, eine Methode zu erstellen, die Daten außerhalb der Klasse const ändert?

class MyClass 
{ 
public: 
    ... 
    void DiscussedMethod() { otherClass->NonConstMethod(); } 

private: 
    OtherClass *otherClass; 
}; 

Ich habe eine Klasse MyClass die einen Zeiger auf OtherClass hält. In.ruft es OtherClass::NonConstMethod auf, das einige sichtbare Daten ändert.

Ich würde gerne wissen, ob es eine gute Praxis wäre, die DiscussedMethodconst zu machen (da es keine Mitgliedsdaten ändert)? Wäre es eine schlechte Übung? Oder ist beides in Ordnung?

Was, wenn die OtherClass einen Zeiger auf die MyClass und in NonConstMethod einige der Daten "MyClass modifizierte gehalten (was bedeutet, dass die MyClass Mitgliedsdaten während des DiscussedMethod Anrufs ändern würden). Wäre es eine schlechte Übung, die DiscussedMethodconst dann zu machen?

Soweit ich habe in der Lage gewesen, die const auf ein Verfahren, um herauszufinden, ist meist ein Code, was zu dokumentieren, so würde ich wahrscheinlich neigen zu nicht den DiscussedMethodconst machen, aber ich möchte Ihre Meinung hören.

EDIT: Einige Antworten nehmen die berücksichtigt, ob das Objekt darauf durch otherClass durch das MyClass Objekt gehört. Dies ist in dem Szenario, mit dem ich arbeite, nicht der Fall. Nehmen wir an, dass beide Objekte unabhängig nebeneinander existieren (mit der Fähigkeit, sich gegenseitig zu ändern). Ich denke, diese Analogie beschreibt meine Situation ziemlich gut.

Betrachten Sie zum Beispiel etwas wie doppelt verknüpfte Liste, wobei jedes Element eine Klasse ist, die Zeiger auf seine Nachbarn und Elementvariable hält. Und es hat Methode MakeNeighboursRed, die die color seiner Nachbarn ändert, aber nicht den Zustand des aufrufenden Objekts selbst beeinflusst. Sollte ich darüber nachdenken, diese Methode const zu machen?

Und was, wenn es eine Möglichkeit gäbe, dass MakeNeighboursRed Nachbarn MakeNeighboursRed aufrufen würde. Am Ende würde sich also auch der Zustand des Objekts ändern, für das ursprünglich MakeNeighboursRed aufgerufen wurde.

Und ich möchte Ihnen allen für Ihre Meinungen danken :-)

+1

Dies ist nur meine persönliche Meinung. Manchmal wies das Objekt darauf hin, dass ich "Teil des Hauptobjekts" betrachte. Das heißt, ich hätte 'OtherClass' wahrscheinlich zu einem Vollmitglied gemacht, aber es musste dynamisch/polymorph/etc sein. In diesem Fall würde ich die Funktion nicht konstant machen, auch wenn es möglich wäre. –

+0

In Bezug auf Ihre Bearbeitung: Ich bleibe bei meiner Antwort: Wenn das Aufrufen einer Methode den Zustand Ihres Objekts ändern kann, sollte es nicht const sein. (Das heißt, Sie ändern den Nachbarn, der wiederum diesen Zustand möglicherweise ändert.) Ich würde eine const-Methode erwarten, um den Zustand des Objekts zu erhalten. – Pixelchemist

Antwort

6

Wenn MyClass die OtherClass Instanz besitzt, würde ich nicht DiscussedMethod konstant machen.

Das gleiche gilt für Klassen, Verwalten von Ressourcen. I.e. Die Standardcontainer geben keine Const-Referenzen oder Zeiger auf den verwalteten Speicher zurück, die const-Funktionen verwenden, obwohl dies "möglich" wäre (da der eigentliche Zeiger, der die Ressource enthält, nicht geändert wird).

Betrachten

class MyClass 
{ 
public: 
    bool a() const { return otherClass->SomeMethod(); } 
    void b() const { otherClass->NonConstMethod(); } 
private: 
    OtherClass *otherClass; 
}; 

void foo (MyClass const &x) 
{ 
    cout << boolalpha << x.a() << endl; 
    x.b(); // possible if b is a const function 
    cout << boolalpha << x.a() << endl; 
} 

Die foo zwei verschiedene Werte drucken konnten, obwohl ein Implementierer von foo wahrscheinlich würde erwarten, dass zwei Funktion auf ein konstantes Objekt ruft das gleiche Verhalten.

Zur Klarstellung:

Das folgende ist ungültig nach der Norm, da die const-Version von operator[] kehrt std::vector<T>::const_reference, die eine konstante Referenz auf den Wert-Typ ist.

std::vector<int> const a = { /* ... */ }; 
a[0] = 23; // impossible, the content is part of the state of a 

Es wäre möglich, wenn es nur eine Unterschrift dieser Funktion ist, nämlich referece operator[] (size_t i) const;, da der Betrieb nicht die internen Zeiger des Vektors ändert aber die Erinnerung sie zu zeigen.

Aber der Speicher, der vom Vektor verwaltet wird, wird als Teil des Zustands der Vektoren betrachtet, und daher ist eine Modifikation durch die konstante Vektorschnittstelle unmöglich.

Wenn der Vektor Zeiger enthält, sind diese Zeiger immer noch nicht über die öffentliche Vektorschnittstelle const veränderbar, obwohl die im Vektor gespeicherten Zeiger möglicherweise nicht konstant sind und es möglich sein könnte, den Speicher, auf den sie zeigen, zu ändern.

std::vector<int*> const b = { /* ... */ }; 
int x(2); 
b[0] = &x; // impossible, b is const 
*b[0] = x; // possible since value_type is int* not int const * 
+0

'" Die Standardcontainer geben keine Const-Referenzen oder Zeiger auf den verwalteten Speicher mit Hilfe von const-Funktionen zurück "' Bitte erläutern Sie und betrachten Sie: const vector v = {..}; * v [0] = 2; ' –

+0

@NeilKirk: In Ihrem Beispiel gibt' v [0] 'einen konstanten Verweis auf einen nicht konstanten Zeiger auf int zurück. '* v [0] = 2;' ändert den Zeiger nicht, sondern den Speicher, auf den der Zeiger zeigt. ('v [0] = & some_int;' wäre unmöglich) Im Wesentlichen zeigt es das gleiche "Problem"/Verhalten wie die Frage selbst ('T * const' ist nicht dasselbe wie' T * const * '). – Pixelchemist

+0

' otherClass -> NonConstMethod(); 'verändert den Zeiger nicht, aber der Speicher, auf den er zeigt (potentiell) und der Operator [] ist in diesem Fall const. –

4

In OOP-Objekt sollte durch seinen Zustand, erhältlich durch seine Schnittstelle vollständig beschrieben werden. Daher sollten konstante Methoden den Zustand des Objekts nicht ändern, wenn diese Änderungen über die Schnittstelle beobachtet werden können.

Ein gutes Beispiel ist ein mutable Mutex innerhalb Ihrer Klasse, um einige gemeinsame Ressourcen zu schützen. Es könnte von der Methode const modifiziert werden, da es keine über die Klassenschnittstelle beobachtbaren Änderungen einführt.

3

Allgemeine Faustregel ist, dass, wenn Sie eine Elementfunktion const machen können, Sie wahrscheinlich sollten. Der Grund dafür ist, dass Sie unbeabsichtigtes Verhalten und Bug einfacher fangen können.

Ein weiteres Argument zugunsten wäre, dass, wenn Sie diese Funktion als const haben Sie dürfen es auf const Objekt aufrufen, so ist es nicht wirklich eine Dokumentation Sache.

1

Es ist total falsch, DiscussedMethodconst zu machen, da es seinen *this Zustand ändert. Das einzige Schlupfloch dazu ist nicht-logisch-Teil-of-Objekt-Status Mitglied Daten mutable, so dass sie in const Funktionen geändert werden können. Dies würde Dinge wie ein Mitglied sein, die eine Zählung für "Anzahl der Male Funktion x() wurde aufgerufen" halten. Jedes andere Element ist Teil des Status des Objekts, und wenn eine Funktion es ändert (unter beliebig Ebene), ist diese Funktion nicht const.

+0

Was meinst du mit total inkorrekt? Es kompiliert, also muss es ein bisschen korrekt sein *. Technisch verändert es '* this ', soweit es den Compiler betrifft. (* witz) –

+0

Ich meine, es ist einfach ans einfach * falsch * :) –

1

Ich würde gerne wissen, ob es eine gute Praxis wäre, das DiscussedMethod const zu machen (da es keine Memberdaten modifiziert)?

otherClassist Mitgliedsdaten, und sie (oder besser gesagt, das Objekt verweist er auf) geändert wird.

Betrachten Sie die Semantik sollte der Zeiger auf otherClass zu einem vollständig im Besitz befindlichen Objekt refaktoriert werden ... ob etwas als ein Zeiger gehalten wird, Referenz oder Objekt ändert nicht die semantische Besitz, IMO.

+1

Wir haben nicht genug Kontext, um zu wissen, ob 'otherClass' die Semantik eines vollständigen Objekts hat. Betrachte 'const vector v = {..}; * v [0] = 2; ' –

2

Insgesamt hängt es davon ab, was die andere Klasse ist. Es ist nicht schwarz und weiß ...

Wenn otherClass ein Protokoll-Objekt (zum Beispiel) ist und Sie die Operation des aktuellen Objekts protokollieren möchten, dann ist es völlig in Ordnung, es aus einer const-Funktion aufzurufen.

Wenn die otherClass ist ein Container, der für das Design (oder Implementierung) Zwecke als separates Objekt implementiert wird als effektiv eine konstante Funktion das Objekt modifiziert dass das eine sehr schlechte Idee.

Ich hoffe, das hilft.

Verwandte Themen