C ++ 상수 사용법 설명


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

누군가 각 const의 사용법을 설명 할 수 있습니까?


27
복잡한 선언을 해독하는이 방법이 정말 마음에 듭니다
Jason

답변:


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 (Plain Old Data) 유형이며 일반적으로 값으로 전달되어야합니다.


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라는 멤버 함수 로 읽을 수 있습니다 .Method3constint constconst intconstint constconst int

(Nb # 2 는 완전히 불필요 합니다.)


22

우선은 const T동일합니다 T const.

const int* const따라서는 int const * const.

const토큰과 포인터 가 많은 표현식을 읽을 때는 항상 오른쪽에서 왼쪽 으로 읽으십시오 (위의 변환을 적용한 후). 따라서이 경우 반환 값은 constint 에 대한 const 포인터 입니다. const반환 값이 수정할 수있는 lvalue가 아니기 때문에 포인터 자체를 만드는 것은 의미가 없습니다. const그러나 pointee를 만들면 호출자가에서 반환 한 int(또는의 배열)을 수정할 수 없습니다 .intMethod3

const int*const&해진다 int const*const&그것이 그래서, CONST에 CONST 포인터 참조int . 참조에 의해 const 포인터를 전달하는 것도 의미가 없습니다. 포인터가 const있고 참조와 포인터가 동일한 저장소를 차지하므로 공간 절약도 없기 ​​때문에 참조 값을 수정할 수 없습니다 .

마지막 const은 메서드가 this개체를 수정하지 않음을 나타냅니다 . this메소드 본문 내에서 포인터는 (이론적) 선언을해야합니다 T const * const this. 이것은 const T*객체가를 호출 할 수 있음을 의미합니다 T::Method3().


2
부분적 const으로는 문구의 머리 부분에 첫 번째 s를 넣지 않으면 모든 것이 더 합리적이라는 점을 지적하기 위해 이것 (및 ildjarn의 유사한 답변)에 투표 하십시오. 이것이 const언어가 허용하더라도 거기 에 넣는 것이 나쁜 습관이라고 생각하는 이유 이며 가장 일반적인 사용법입니다.
TED

12

의 규칙을 기억하는 쉬운 방법 const은 다음과 같이 생각 const하는 것입니다. 왼쪽에 아무것도 없으면 왼쪽에있는 것에 적용됩니다.

따라서의 경우 const int * const첫 번째 const는 왼쪽에 아무것도 없으므로 적용되고 int두 번째 const에는 왼쪽에 무언가가 있으므로 포인터에 적용됩니다.

이 규칙은 또한 const int const *. int이 표현식 에 대한 두 const 적용 은 중복되므로 유효하지 않습니다.


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

디코딩을 위해 식별자 이름 (이 경우 ) 에서 시작 하여 왼쪽에서 오른쪽에서 뒤에서 왼쪽으로 앞뒤로 읽는 "clock"또는 "spiral"방법 을 사용하고 싶습니다 Method3. 명명 규칙. const int* const Method3(const int* const&) const클래스 멤버 (이름이 지정되지 않은 클래스)를 변경하지 않고 상수를 가리키는 포인터에 대한 상수 참조를 가져와 상수에 대한 int상수 포인터를 반환 하는 클래스 메서드도 마찬가지 입니다 int.

도움이 되었기를 바랍니다,

제이슨


2

C ++에서 const를 기억하는 쉬운 방법은 다음과 같은 형식의 코드를 볼 때입니다.

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 int에 Method3대한 const 포인터를 반환하는 호출 된 const int에 대한 const 포인터에 대한 참조를받는 const 메서드입니다 .

  1. const 메서드는 멤버를 수정할 수 없습니다 (빠른 경우가 아니면 mutable)
  2. const 포인터는 다른 것을 가리 키도록 변경할 수 없습니다.
  3. const int (또는 다른 유형)는 수정할 수 없습니다.

1

const # 1 : Method3에서 반환 된 포인터는 const int를 참조합니다.

const # 2 : 함수 자체가 반환하는 포인터 값은 const입니다. 함수의 반환 값이 l- 값이 될 수 없기 때문에 이것은 쓸모없는 const입니다 (그래도 유효하지만).

const # 3 : 함수 참조로 전달 된 포인터 유형은 const int를 가리 킵니다.

const # 4 : 함수에 대한 참조로 전달되는 포인터 값은 그 자체로 const 포인터입니다. 함수에 전달되는 값을 const로 선언하는 것은 일반적으로 무의미하지만이 값은 참조로 전달되므로 의미가있을 수 있습니다.

const # 5 : 함수 (아마도 멤버 함수)가 const입니다. 즉, (a) 자신이 속한 개체의 멤버에 새 값을 할당하거나 (b) 상수가 아닌 멤버 함수를 호출 할 수 없습니다. 개체 또는 그 구성원 중 하나에.


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

이게 도움이 되길 바란다!

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.