const int* const Method3(const int* const&) const;
Может кто-нибудь объяснить использование каждой из констант?
Ответы:
Прочтите это: https://isocpp.org/wiki/faq/const-correctness
Финал const означает, что функция Method3не изменяет неизменяемые члены своего класса.
const int* const означает постоянный указатель на константу int: то есть указатель, который не может быть изменен, на int, который не может быть изменен: единственная разница между this и 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(или const int, если хотите) и возвращает constуказатель на int const(const int ).
(Nb # 2 совершенно излишне .)
Прежде всего const TэквивалентенT const .
const int* const поэтому эквивалентно int const * const .
При чтении выражений с большим количеством constтокенов и указателей всегда старайтесь читать их справа налево (после применения преобразования, описанного выше). Итак, в этом случае возвращаемое значение является указателем const на константуint . Создание самого указателя constздесь не имеет смысла, поскольку возвращаемое значение не является lvalue, которое можно изменить. Однако создание указателя constгарантирует, что вызывающий не может изменять int(или массив ints), возвращаемыйMethod3 .
const int*const&становится int const*const&, поэтому это ссылка на константный указатель на константуint . Передача константного указателя по ссылкам male тоже не имеет смысла - вы не можете изменить указанное значение, поскольку указатель есть, constа ссылки и указатели занимают одинаковую память, поэтому нет никакой экономии места.
Последнее constуказывает на то, что метод не изменяет thisобъект. thisУказатель внутри тела метода будет иметь (теоретически) заявление T const * const this. Это означает, что const T*объект сможет вызывать T::Method3().
consts в начало фразы. Именно поэтому я считаю, что это плохая практика const, даже если язык позволяет это, и это наиболее распространенное использование.
Легкий способ запомнить правила const- это думать об этом так: constприменимо к объекту слева от него, если слева от него ничего нет.
Итак, в случае const int * constс первой константой слева ничего нет, поэтому она применяется к, intа вторая имеет что-то слева, поэтому она применяется к указателю.
Это правило также говорит вам, что произойдет в том случае, если у вас есть const int 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 .
Надеюсь это поможет,
Джейсон
Самый простой способ запомнить константу в 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: указатель, возвращаемый Method3, ссылается на const int.
const # 2: значение указателя, возвращаемое самой функцией, равно const. Это бесполезная константа (хотя грамматически правильная), потому что возвращаемое значение из функции не может быть l-значением.
const # 3: Тип указателя, переданный по ссылке в функцию, указывает на const int.
const # 4: значение указателя, переданное по ссылке в функцию, само является константным указателем. Объявление значения, которое передается функции как const, обычно бессмысленно, но это значение передается по ссылке, поэтому оно может иметь смысл.
const # 5: функция (предположительно, функция-член) является константой, что означает, что ей не разрешено (а) назначать новые значения любым членам объекта, частью которого она является, или (б) вызывать неконстантную функцию-член на объекте или на любом из его членов.
const в конце метода стоит квалификатор, означающий, что состояние объекта не будет изменено.
const int*const&означает получение по ссылке константного указателя на константное местоположение. Он не может ни указывать на другое местоположение, ни изменять значение, на которое указывает.
const int*const - это возвращаемое значение, которое также является постоянным указателем на постоянное местоположение.
Несколько примеров могут быть хороши для демонстрации этой концепции, чем больше, тем лучше 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;
}
};
Надеюсь, это поможет!