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
(или массив int
s), возвращаемыйMethod3
.
const int*const&
становится int const*const&
, поэтому это ссылка на константный указатель на константуint
. Передача константного указателя по ссылкам male тоже не имеет смысла - вы не можете изменить указанное значение, поскольку указатель есть, const
а ссылки и указатели занимают одинаковую память, поэтому нет никакой экономии места.
Последнее const
указывает на то, что метод не изменяет this
объект. this
Указатель внутри тела метода будет иметь (теоретически) заявление T const * const this
. Это означает, что const T*
объект сможет вызывать T::Method3()
.
const
s в начало фразы. Именно поэтому я считаю, что это плохая практика 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;
}
};
Надеюсь, это поможет!