Antworten:
Lesen Sie dies: https://isocpp.org/wiki/faq/const-correctness
Das letzte constbedeutet, dass die Funktion Method3die nicht veränderlichen Mitglieder ihrer Klasse nicht ändert.
const int* constbedeutet einen konstanten Zeiger auf eine Konstante int: dh einen Zeiger, der nicht geändert werden kann, auf einen int, der nicht geändert werden kann: Der einzige Unterschied zwischen dieser und der const int&besteht darin, dass dies möglich istnull
const int* const&bedeutet eine Referenz auf einen konstanten Zeiger auf eine Konstante int. Normalerweise werden Zeiger nicht als Referenz übergeben. const int* &Dies ist sinnvoller, da dies bedeuten würde, dass der Zeiger während des Methodenaufrufs geändert werden könnte. Dies ist der einzige Grund, warum ich sehe, dass ein Zeiger als Referenz übergeben const int* const&wird. Dies ist in jeder Hinsicht dasselbe, const int* constaußer dass er wahrscheinlich weniger effizient ist Da Zeiger einfache POD-Typen (Old Data) sind, sollten diese im Allgemeinen als Wert übergeben werden.
Es ist einfacher zu verstehen, wenn Sie dies als das völlig Äquivalent umschreiben
// v───v───v───v───v───v───v───v───v───v───v───v─┬┐
// ││
// v──#1 v─#2 v──#3 v─#4 #5
int const * const Method3(int const * const&) const;
dann lies es von rechts nach links.
# 5 besagt, dass die gesamte Funktionsdeklaration links ist const, was impliziert, dass dies notwendigerweise eine Mitgliedsfunktion und keine freie Funktion ist.
# 4 besagt, dass der Zeiger links ist const(darf nicht geändert werden, um auf eine andere Adresse zu zeigen).
# 3 besagt, dass das intlinks ist const(darf nicht geändert werden, um einen anderen Wert zu haben).
# 2 sagt, dass der Zeiger nach links ist const.
# 1 sagt, dass das intauf der linken Seite ist const.
Wenn Sie alles zusammenfassen, können Sie dies als eine constMitgliedsfunktion mit dem Namen lesen Method3, die einen Verweis auf einen constZeiger auf ein int const(oder ein const int, wenn Sie es vorziehen) verwendet und einen constZeiger auf ein int const( const int) zurückgibt .
(Nb # 2 ist völlig überflüssig .)
Erstens const Tist gleichbedeutend mit T const.
const int* constist daher gleichbedeutend mit int const * const.
constVersuchen Sie beim Lesen von Ausdrücken mit vielen Token und Zeigern immer, sie von rechts nach links zu lesen (nachdem Sie die obige Transformation angewendet haben). In diesem Fall ist der Rückgabewert ein const-Zeiger auf eine constint . Das constErstellen des Zeigers selbst macht hier keinen Sinn, da der Rückgabewert kein Wert ist, der geändert werden könnte. Durch das Erstellen des Pointees constwird jedoch garantiert, dass der Aufrufer das von zurückgegebene int(oder Array von ints) nicht ändern darf Method3.
const int*const&wird int const*const&, so ist es eine Referenz auf einen const Zeiger auf eine constint . Das Übergeben eines const-Zeigers durch männliche Referenzen macht ebenfalls keinen Sinn - Sie können den referenzierten Wert nicht ändern, da der Zeiger ist constund Referenzen und Zeiger den gleichen Speicherplatz belegen, sodass auch keine Platzersparnis entsteht.
Der letzte constgibt an, dass die Methode das thisObjekt nicht ändert . Der thisZeiger innerhalb des Methodenkörpers hat die (theoretische) Deklaration T const * const this. Dies bedeutet, dass ein const T*Objekt aufrufen kann T::Method3().
consts an die Spitze der Phrase setzen. Dies ist genau der Grund, warum ich denke, dass es eine schlechte Praxis ist, sie constdort zu platzieren, obwohl die Sprache dies zulässt und es die häufigste Verwendung ist.
Eine einfache Möglichkeit, sich an die Regeln von zu erinnern, constbesteht darin, folgendermaßen darüber nachzudenken: constGilt für das Ding auf der linken Seite, es sei denn, es befindet sich nichts auf der linken Seite.
Im Fall von const int * consthat die erste Konstante nichts auf der linken Seite, also gilt sie für intund die zweite hat etwas auf der linken Seite, also gilt sie für den Zeiger.
Diese Regel sagt Ihnen auch, was in dem Fall passieren würde, in dem Sie haben const int const *. Da beide Konstanten für intdiesen Ausdruck gelten, ist er redundant und daher ungültig.
const /* don't modify the int or array of ints' value(s) */
int* const /* as a retval, ignored. useless declaration */
Method3(const /* don't modify the int or array of ints' value(s) */
int* const /* don't modify the pointer's value, the address to which `pointer` points to. e.g. you cannot say `++pointer` */
&) const; /* this method does not modify the instance/object which implements the method */
Ich verwende gerne die "Clock" - oder "Spiral" -Methode, bei der Sie ausgehend vom Bezeichnernamen (in diesem Fall Method3) von links nach rechts, von links nach links usw. hin und her lesen, um zu dekodieren Regeln der Namensgebung. Dies const int* const Method3(const int* const&) constgilt auch für eine Klassenmethode, die keine Klassenmitglieder (einer nicht benannten Klasse) ändert und einen konstanten Verweis auf einen Zeiger verwendet, der auf eine Konstante zeigt intund einen konstanten Zeiger auf eine Konstante zurückgibt int.
Hoffe das hilft,
Jason
Eine einfache Möglichkeit, sich an die Konstante in C ++ zu erinnern, besteht darin, Code in folgender Form zu sehen:
XXX const;
const YYY;
XXX, JJJ wird eine konstante Komponente sein,
XXX constForm:
function ( def var ) const; ------#1
* const; ------#2
const YYY bilden:
const int; ------#3
const double;
Leute benutzen normalerweise diese Typen. Wenn Sie "const&"irgendwo sehen, fühlen Sie sich nicht verwirrt, const beschreibt etwas vor sich. Die Antwort auf dieses Problem liegt nun auf der Hand.
const int* const Method3(const int* const&) const;
| | | | |
#3 #2 #3 #2 #1
Ich möchte nur erwähnen, dass dies const int* const&in der Tat ein ständiger Hinweis ist const int*. Beispielsweise:
int i = 0;
int j = 1;
int* p = &i;
int* q = &j;
const int* const& cpref = p;
cpref = q; //Error: assignment of read-only reference 'cpref'
Es ist auch der Fall für int* const&, was bedeutet: "Ein ständiger Verweis auf int*".
Ist const int*&aber ein nicht konstanter Verweis auf const int*.
Hoffe das hilft.
Das Lesen von rechts nach links erleichtert das Verständnis von Modifikatoren.
Eine const-Methode, die einen Verweis auf einen const-Zeiger auf eine aufgerufene const int verwendet, Method3die einen const-Zeiger auf eine const int zurückgibt.
mutable)const # 1: Der von Methode3 zurückgegebene Zeiger verweist auf eine const int.
const # 2: Der von der Funktion selbst zurückgegebene Zeigerwert ist const. Dies ist eine nutzlose Konstante (obwohl grammatisch gültig), da der Rückgabewert einer Funktion kein l-Wert sein kann.
const # 3: Der Zeigertyp, der als Referenz auf die Funktion übergeben wird, zeigt auf eine const int.
const # 4: Der Zeigerwert, der als Verweis auf die Funktion übergeben wird, ist selbst ein const-Zeiger. Das Deklarieren eines Werts, der an eine Funktion als const übergeben wird, ist normalerweise sinnlos, aber dieser Wert wird als Referenz übergeben, sodass er sinnvoll sein kann.
const # 5: Die Funktion (vermutlich eine Mitgliedsfunktion) ist const, was bedeutet, dass es nicht erlaubt ist, (a) Mitgliedern des Objekts, zu dem sie gehört, neue Werte zuzuweisen oder (b) eine Nicht-const-Mitgliedsfunktion aufzurufen auf dem Objekt oder einem seiner Mitglieder.
const Am Ende der Methode befindet sich das Qualifikationsmerkmal, das angibt, dass der Status des Objekts nicht geändert wird.
const int*const&bedeutet, dass durch Verweisen ein const-Zeiger auf eine const-Position empfangen wird. Es kann weder geändert werden, um auf eine andere Position zu zeigen, noch den Wert ändern, auf den es zeigt.
const int*const ist der Rückgabewert, der auch ein konstanter Zeiger auf eine konstante Position ist.
Ein paar Beispiele könnten nett sein, um dieses Konzept zu demonstrieren, je mehr desto besser imho.
class TestClass
{
private:
int iValue;
int* oValuePtr;
int& oValueRef;
public:
int TestClass::ByValMethod1(int Value)
{
// Value can be modified
Value++;
// iValue can be modified
iValue = Value;
iValue += 1;
// Return value can be modified
return ++iValue;
}
int TestClass::ByValMethod2(const int Value)
{
// Value *cannot* be modified
// Variable is const variable
Value++;
// iValue can be modified
iValue = Value;
iValue += 1;
// Return value can be modified
return ++iValue;
}
const int TestClass::ByValMethod3(int Value)
{
// Value can be modified
Value++;
// iValue can be modified
iValue = Value;
iValue += 1;
// Return value can be modified
return ++iValue;
}
const int TestClass::ByValMethod4(const int Value)
{
// Value *cannot* be modified
// Variable is const variable
Value++;
// iValue can be modified
iValue = Value;
iValue += 1;
// Return value can be modified
return ++iValue;
}
const int TestClass::ByValMethod5(const int Value) const
{
// Value *cannot* be modified
// Variable is const variable
Value++;
// iValue *cannot* be modified
// Access through a const object
iValue = Value;
iValue += 1;
// Return value *cannot* be modified
// Access through a const object
return ++iValue;
}
int& TestClass::ByRefMethod1(int& Value)
{
// Value can be modified
Value++;
// oValueRef can be modified
oValueRef = Value;
oValueRef += 1;
// Return value can be modified
return ++oValueRef;
}
int& TestClass::ByRefMethod2(const int& Value)
{
// Value *cannot* be modified
// Variable is const variable
Value++;
// oValueRef can be modified
oValueRef = Value;
oValueRef += 1;
// Return value can be modified
return ++oValueRef;
}
const int& TestClass::ByRefMethod3(int& Value)
{
// Value can be modified
Value++;
// oValueRef can be modified
oValueRef = Value;
oValueRef += 1;
// Return value can be modified
return ++oValueRef;
}
const int& TestClass::ByRefMethod4(const int& Value)
{
// Value *cannot* be modified
// Variable is const variable
Value++;
// oValueRef can be modified
oValueRef = Value;
oValueRef += 1;
// Return value can be modified
return ++oValueRef;
}
const int& TestClass::ByRefMethod5(const int& Value) const
{
// Value *cannot* be modified
// Variable is const variable
Value++;
// oValueRef can be modified
oValueRef = Value;
oValueRef += 1;
// Return value can be modified
return ++oValueRef;
}
int* TestClass::PointerMethod1(int* Value)
{
// Value can be modified
Value++;
// oValuePtr can be assigned
oValuePtr = Value;
// oValuePtr can be modified
oValuePtr += 1;
// Return value can be modified
return ++oValuePtr;
}
int* TestClass::PointerMethod2(const int* Value)
{
// Value can be modified
Value++;
// oValuePtr cannot be assigned
// const int* to int*
oValuePtr = Value;
// oValuePtr can be modified
oValuePtr += 1;
// Return value can be modified
return ++oValuePtr;
}
const int* TestClass::PointerMethod3(int* Value)
{
// Value can be modified
Value++;
// oValuePtr can be assigned
oValuePtr = Value;
// iValue can be modified
oValuePtr += 1;
// Return value can be modified
return ++oValuePtr;
}
const int* TestClass::PointerMethod4(const int* Value)
{
// Value cannot be modified
Value++;
// oValuePtr *cannot* be assigned
// const int* to int*
oValuePtr = Value;
// oValuePtr can be modified
oValuePtr += 1;
// Return value can be modified
return ++oValuePtr;
}
const int* TestClass::PointerMethod5(const int* Value) const
{
// Value can be modified
++Value;
// oValuePtr *cannot* be assigned
// const int* to int* const
// Access through a const object
oValuePtr = Value;
// oValuePtr *cannot* be modified
// Access through a const object
oValuePtr += 1;
// Return value *cannot* be modified
return ++oValuePtr;
}
};
Ich hoffe das hilft!