const int* const Method3(const int* const&) const;
Czy ktoś może wyjaśnić użycie każdej z const?
Odpowiedzi:
Przeczytaj to: https://isocpp.org/wiki/faq/const-correctness
Ostatnia const
oznacza, że funkcja Method3
nie modyfikuje niezmiennych elementów swojej klasy.
const int* const
oznacza stały wskaźnik do stałej int: tj. wskaźnik, którego nie można zmienić, do int, którego nie można zmienić: jedyna różnica między tym a const int&
polega na tym, że może byćnull
const int* const&
oznacza odniesienie do stałego wskaźnika do stałej int. Zazwyczaj wskaźniki nie są przekazywane przez odniesienie; const int* &
ma więcej sensu, ponieważ oznaczałoby to, że wskaźnik można zmienić podczas wywołania metody, co byłoby jedynym powodem, dla którego widzę, aby przekazać wskaźnik przez odniesienie, const int* const&
jest do wszystkich intencji i celów takie same, const int* const
z wyjątkiem tego, że jest prawdopodobnie mniej wydajne Ponieważ wskaźniki są zwykłymi starymi typami danych (POD) i generalnie powinny być przekazywane przez wartość.
Łatwiej jest zrozumieć, jeśli przepiszesz to jako całkowicie równoważne
// 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;
następnie przeczytaj go od prawej do lewej.
# 5 mówi, że cała deklaracja funkcji po lewej stronie to const
, co oznacza, że jest to koniecznie funkcja składowa, a nie funkcja wolna.
# 4 mówi, że wskaźnik po lewej stronie to const
(nie można go zmienić, aby wskazywał na inny adres).
# 3 mówi, że po int
lewej stronie jest const
(nie można go zmienić, aby miał inną wartość).
# 2 mówi, że wskaźnik po lewej to const
.
# 1 mówi, że int
po lewej stronie jest const
.
Łącząc to wszystko razem, możesz to odczytać jako const
funkcję składową Method3
o nazwie, która pobiera odwołanie do const
wskaźnika do int const
(lub const int
, jeśli wolisz) i zwraca const
wskaźnik do int const
( const int
).
(Uwaga nr 2 jest całkowicie zbędna ).
Przede wszystkim const T
jest odpowiednikiem T const
.
const int* const
jest zatem równoważne z int const * const
.
Czytając wyrażenia z dużą ilością const
tokenów i wskaźników, zawsze staraj się czytać je od prawej do lewej (po zastosowaniu powyższej transformacji). W tym przypadku wartość zwracana jest wskaźnikiem stałej do stałejint
. Samo tworzenie wskaźnika nie const
ma tutaj sensu, ponieważ zwracana wartość nie jest lwartością, którą można by zmodyfikować. Wskazanie const
jednak gwarantuje, że wywołujący nie może modyfikować int
(lub tablicy int
s) zwróconej przez Method3
.
const int*const&
staje się int const*const&
, więc jest to odniesienie do stałej wskaźnika do stałejint
. Przekazywanie wskaźnika do stałej przez referencje męskie również nie ma sensu - nie możesz modyfikować wartości, do której się odwołujesz, ponieważ wskaźnik jest, const
a referencje i wskaźniki zajmują taką samą pamięć, więc nie ma również żadnych oszczędności miejsca.
Ostatnia const
wskazuje, że metoda nie modyfikuje this
obiektu. this
Wskaźnik w organizmie metoda będzie miał (teoretyczna) oświadczenie T const * const this
. Oznacza to, że const T*
obiekt będzie mógł wywołać T::Method3()
.
const
frazy. Właśnie dlatego uważam, że umieszczanie go w tym miejscu jest złą praktyką const
, mimo że język na to pozwala, i jest to najpowszechniejsze użycie.
Łatwym sposobem na zapamiętanie zasad programu const
jest myślenie o tym w ten sposób: const
dotyczy rzeczy po lewej stronie, chyba że nic nie ma po lewej stronie.
Tak więc w przypadku const int * const
pierwszej stałej nie ma nic po lewej stronie, więc odnosi się do, int
a druga ma coś po lewej stronie, więc odnosi się do wskaźnika.
Ta reguła mówi również, co by się stało, gdybyś miał const int const *
. Ponieważ obie const mają zastosowanie do int
tego wyrażenia, jest zbędne, a zatem nieważne.
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 */
Lubię używać metody "zegara" lub "spirali", gdzie zaczynając od nazwy identyfikatora (w tym przypadku Method3
) czytasz tam iz powrotem od lewej do prawej, z powrotem do lewej itd. W celu dekodowania konwencje nazewnictwa. const int* const Method3(const int* const&) const
Jest to więc metoda klasy, która nie zmienia żadnych składowych klasy (jakiejś nienazwanej klasy) i przyjmuje stałe odwołanie do wskaźnika, który wskazuje na stałą, int
i zwraca stały wskaźnik do stałej int
.
Mam nadzieję że to pomoże,
Jason
Łatwym sposobem na zapamiętanie stałej w C ++ jest widok kodu w postaci:
XXX const;
const YYY;
XXX, YYY będzie składnikiem stałym w
XXX const
postaci:
function ( def var ) const; ------#1
* const; ------#2
const YYY
Formularz:
const int; ------#3
const double;
Ludzie zwykle używają tych typów. Kiedy "const&"
gdzieś widzisz , nie czuj się zdezorientowany, const opisuje coś przed sobą. więc odpowiedź na ten problem jest teraz oczywista.
const int* const Method3(const int* const&) const;
| | | | |
#3 #2 #3 #2 #1
Chcę tylko wspomnieć, że const int* const&
jest to rzeczywiście stałe odniesienie do const int*
. Na przykład:
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'
Dotyczy to również int* const&
, co oznacza: „Stałe odniesienie do int*
”.
Ale const int*&
jest to niestałe odniesienie do const int*
.
Mam nadzieję że to pomoże.
Czytanie od prawej do lewej ułatwia zrozumienie modyfikatorów.
Metoda const, która przyjmuje odwołanie do stałego wskaźnika do stałej int o nazwie, Method3
która zwraca wskaźnik do stałej wartości stałej int.
mutable
)const # 1: wskaźnik zwrócony przez Method3 odnosi się do stałej int.
const # 2: Wartość wskaźnika zwracana przez samą funkcję to const. Jest to bezużyteczna stała (choć poprawna gramatycznie), ponieważ wartość zwracana przez funkcję nie może być wartością l.
const # 3: typ wskaźnika przekazany przez odniesienie do funkcji wskazuje na stałą int.
const # 4: Wartość wskaźnika przekazana przez odniesienie do funkcji jest sama w sobie wskaźnikiem do stałej. Deklarowanie wartości, która jest przekazywana do funkcji jako const normalnie byłoby bezcelowe, ale ta wartość jest przekazywana przez odwołanie, więc może mieć znaczenie.
const # 5: Funkcja (prawdopodobnie funkcja składowa) jest stała, co oznacza, że nie można (a) przypisywać nowych wartości żadnym członom obiektu, którego jest częścią lub (b) wywoływać funkcji niebędącej składową stałą na obiekcie lub którymkolwiek z jego członków.
const
na końcu metody znajduje się kwalifikator oznaczający, że stan obiektu nie zostanie zmieniony.
const int*const&
oznacza otrzymywanie przez odwołanie wskaźnika do stałej lokalizacji. Nie może się zmienić, aby wskazywać inną lokalizację, ani zmienić wartości, na którą wskazuje.
const int*const
jest wartością zwracaną, która jest również stałym wskaźnikiem do stałej lokalizacji.
Kilka przykładów może być fajnych, aby zademonstrować tę koncepcję, im więcej, tym lepsze 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;
}
};
Mam nadzieję, że to pomoże!