Пояснення щодо використання C ++ Const


97
const int* const Method3(const int* const&) const;

Хтось може пояснити використання кожного з const?


27
Мені дуже подобається цей метод розшифровки складних декларацій: c-faq.com/decl/spiral.anderson.html
Джейсон,

Відповіді:


77

Прочитайте це: 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), і вони, як правило, повинні передаватися за значенням.


103

Це легше зрозуміти, якщо ви перепишете це як цілком еквівалент

// 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 є абсолютно зайвим .)


22

Перш за все const Tрівнозначно T const.

const int* constТому еквівалентний int const * const.

Читаючи вирази з великою кількістю constлексем і покажчиків, завжди намагайтеся читати їх справа наліво (після застосування перетворення вище). Отже, у цьому випадку повернене значення є показником const на constint . Створення самого вказівника constтут не має сенсу, оскільки значення повернення не є значенням, яке можна змінити. constОднак вказівник гарантує, що абонент може не змінювати int(або масив ints), що повертається Method3.

const int*const&стає int const*const&, тож це посилання на покажчик const на constint . Передача вказівника const посиланнями чоловічої статі також не має сенсу - ви не можете змінити значення, на яке посилається, оскільки вказівник є, constа посилання та вказівники займають рівне сховище, тому економії місця також немає.

Останнє constвказує на те, що метод не змінює thisоб'єкт. thisПокажчик всередині тіла методу матиме (теоретично) заяву T const * const this. Це означає, що const T*об’єкт зможе викликати T::Method3().


2
Проголосувавши за це (і аналогічну відповідь ildjarn), частково для того, щоб сказати, що все це має більше сенсу, якщо ви не ставите перші consts в голові фрази. Саме тому, я вважаю, що це погана практика const, хоча мова дозволяє це, і це найпоширеніше вживання.
ТЕД

12

Простий спосіб запам'ятати правила - constце думати про нього таким чином: constстосується речі зліва, якщо тільки зліва немає нічого.

Так що у випадку з const int * constпершим const немає ліворуч, тому він стосується, intа другий має щось ліворуч, тому він застосовується до покажчика.

Це правило також повідомляє вам, що могло б статися у випадку, коли у вас є const int const *. Оскільки обидва const застосовуються до intцього виразу надлишковим і тому недійсним.


3
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 */

3

Мені подобається використовувати метод "годинник" або "спіраль", де, починаючи від імені ідентифікатора (у цьому випадку Method3), ви читаєте "вперед-назад" зліва-направо-назад-вліво тощо, щоб розшифрувати конвенції іменування. Таким чином const int* const Method3(const int* const&) const, це метод класу, який не змінює жодного члена класу (якогось не названого класу) і постійно посилається на покажчик, який вказує на константу intі повертає постійний вказівник на константу int.

Сподіваюся, це допомагає,

Джейсон


2

Простий спосіб запам'ятати 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

2

Я хочу лише зазначити, що 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*.
Сподіваюся, це допомагає.


1

Читання справа наліво полегшує розуміння модифікаторів.

Метод const, який приймає посилання на покажчик const на виклик const int, Method3який повертає вказівник const на const int.

  1. Метод const не може змінювати членів (якщо вони не є явними mutable)
  2. Вказівник const не можна змінити, щоб вказувати на щось інше
  3. Const int (або будь-який інший тип) не можна змінити

1

const # 1: Вказівник, повернутий методом3, відноситься до const int.

const # 2: Значення вказівника, повернене функцією, само собою, це const. Це марний const (хоча граматично дійсний), оскільки повернене значення функції не може бути l-значенням.

const # 3: Тип вказівника передається посиланням на функціональні точки до const int.

const # 4: Значення вказівника, передане посиланням на функцію, саме по собі є покажчиком const. Оголошення значення, яке передається функції як const, як правило, є безглуздим, але це значення передається посиланням, тому воно може бути значимим.

const # 5: Функція (імовірно, функція-член) є const, тобто означає, що не дозволяється (а) призначати нові значення будь-яким членам об'єкта, до якого вона входить, або (b) викликати функцію члена, яка не містить const на об'єкті або будь-якому з його учасників.


0
  • const наприкінці методу є класифікатор, що означає стан об'єкта, який не буде змінено.

  • const int*const&означає отримання за допомогою посилання вказівника const на розташування const. Він не може ні змінити, щоб вказати на інше місце, ні змінити значення, на яке вказує.

  • const int*const - це повернене значення, яке також є постійним вказівником на постійне розташування.


0

Декілька прикладів може бути приємно продемонструвати цю концепцію, чим більше, тим краще імхо.

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;
   }
};

Я сподіваюся, що це допомагає!

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.