Відповіді:
Прочитайте це: https://isocpp.org/wiki/faq/const-correctness
Останній const
означає, що функція Method3
не змінює незмінювані члени свого класу.
const int* const
означає постійний вказівник на константу int: тобто вказівник, який не можна змінити, на int, який не можна змінити: єдина різниця між цим і const int&
полягає в тому, що він може бутиnull
const int* const&
означає посилання на константний вказівник на константу int. Зазвичай покажчики не передаються за посиланням; const int* &
має більше сенсу, оскільки це означало б, що вказівник міг бути змінений під час виклику методу, і це було б єдиною причиною, за якою я можу передати вказівник за посиланням, const int* const&
для всіх намірів і цілей однакові, const int* const
за винятком того, що це, ймовірно, менш ефективно оскільки покажчики - це звичайні типи старих даних (POD), і вони, як правило, повинні передаватися за значенням.
Це легше зрозуміти, якщо ви перепишете це як цілком еквівалент
// 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;
потім прочитайте його справа наліво.
№5 говорить, що вся декларація функції зліва є const
, що означає, що це обов’язково функція-член, а не вільна функція.
№4 говорить, що вказівник ліворуч є const
(його не можна змінювати, щоб вказувати на іншу адресу).
№3 говорить, що int
ліворуч є const
(не може бути змінено, щоб мати інше значення).
# 2 говорить, що вказівник ліворуч є const
.
# 1 говорить, що int
ліворуч є const
.
Збираючи все це разом, ви можете прочитати це як const
ім’я-член-член, Method3
який бере посилання на const
вказівник на int const
(або a const int
, якщо ви хочете) і повертає const
вказівник на int const
( const int
).
(Nb №2 є абсолютно зайвим .)
Перш за все const T
рівнозначно T const
.
const int* const
Тому еквівалентний int const * const
.
Читаючи вирази з великою кількістю const
лексем і покажчиків, завжди намагайтеся читати їх справа наліво (після застосування перетворення вище). Отже, у цьому випадку повернене значення є показником const на constint
. Створення самого вказівника const
тут не має сенсу, оскільки значення повернення не є значенням, яке можна змінити. const
Однак вказівник гарантує, що абонент може не змінювати int
(або масив int
s), що повертається Method3
.
const int*const&
стає int const*const&
, тож це посилання на покажчик const на constint
. Передача вказівника const посиланнями чоловічої статі також не має сенсу - ви не можете змінити значення, на яке посилається, оскільки вказівник є, const
а посилання та вказівники займають рівне сховище, тому економії місця також немає.
Останнє const
вказує на те, що метод не змінює this
об'єкт. this
Покажчик всередині тіла методу матиме (теоретично) заяву T const * const this
. Це означає, що const T*
об’єкт зможе викликати T::Method3()
.
const
s в голові фрази. Саме тому, я вважаю, що це погана практика const
, хоча мова дозволяє це, і це найпоширеніше вживання.
Простий спосіб запам'ятати правила - const
це думати про нього таким чином: const
стосується речі зліва, якщо тільки зліва немає нічого.
Так що у випадку з const int * const
першим const немає ліворуч, тому він стосується, int
а другий має щось ліворуч, тому він застосовується до покажчика.
Це правило також повідомляє вам, що могло б статися у випадку, коли у вас є const int const *
. Оскільки обидва const застосовуються до int
цього виразу надлишковим і тому недійсним.
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 */
Мені подобається використовувати метод "годинник" або "спіраль", де, починаючи від імені ідентифікатора (у цьому випадку Method3
), ви читаєте "вперед-назад" зліва-направо-назад-вліво тощо, щоб розшифрувати конвенції іменування. Таким чином const int* const Method3(const int* const&) const
, це метод класу, який не змінює жодного члена класу (якогось не названого класу) і постійно посилається на покажчик, який вказує на константу int
і повертає постійний вказівник на константу int
.
Сподіваюся, це допомагає,
Джейсон
Простий спосіб запам'ятати const у C ++ - це коли ви бачите якийсь код у формі, наприклад:
XXX const;
const YYY;
XXX, YYY буде постійним компонентом,
XXX const
форма:
function ( def var ) const; ------#1
* const; ------#2
const YYY
форма:
const int; ------#3
const double;
Люди зазвичай використовують ці типи. Коли ви "const&"
десь бачите , не відчувайте розгубленості, const описує щось перед собою. тож відповідь на цю проблему зараз напрошується сам собою.
const int* const Method3(const int* const&) const;
| | | | |
#3 #2 #3 #2 #1
Я хочу лише зазначити, що const int* const&
це справді постійне посилання на const int*
. Наприклад:
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'
Це також стосується int* const&
, що означає: "Постійне посилання на int*
".
Але const int*&
є непостійним посиланням на const int*
.
Сподіваюся, це допомагає.
Читання справа наліво полегшує розуміння модифікаторів.
Метод const, який приймає посилання на покажчик const на виклик const int, Method3
який повертає вказівник const на const int.
mutable
)const # 1: Вказівник, повернутий методом3, відноситься до const int.
const # 2: Значення вказівника, повернене функцією, само собою, це const. Це марний const (хоча граматично дійсний), оскільки повернене значення функції не може бути l-значенням.
const # 3: Тип вказівника передається посиланням на функціональні точки до const int.
const # 4: Значення вказівника, передане посиланням на функцію, саме по собі є покажчиком const. Оголошення значення, яке передається функції як const, як правило, є безглуздим, але це значення передається посиланням, тому воно може бути значимим.
const # 5: Функція (імовірно, функція-член) є const, тобто означає, що не дозволяється (а) призначати нові значення будь-яким членам об'єкта, до якого вона входить, або (b) викликати функцію члена, яка не містить const на об'єкті або будь-якому з його учасників.
const
наприкінці методу є класифікатор, що означає стан об'єкта, який не буде змінено.
const int*const&
означає отримання за допомогою посилання вказівника const на розташування const. Він не може ні змінити, щоб вказати на інше місце, ні змінити значення, на яке вказує.
const int*const
- це повернене значення, яке також є постійним вказівником на постійне розташування.
Декілька прикладів може бути приємно продемонструвати цю концепцію, чим більше, тим краще імхо.
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;
}
};
Я сподіваюся, що це допомагає!