C ++ Constの使用法の説明


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

誰かがそれぞれのconstの使い方を説明できますか?


27
私は複雑な宣言を解読するこの方法が本当に好きです:c-faq.com/decl/spiral.anderson.html
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)タイプであり、これらは一般に値で渡される必要があるためです。


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(またはconst intあなたが好む場合、)とを返すconstへのポインタをint constconst int)。

(Nb#2 は完全に不要です。)


22

まず、const Tと同等T constです。

const int* constしたがって、はと同等int const * constです。

多数のconstトークンとポインタが含まれる式を読み取る場合は、常に上記の変換を適用した後、右から左読み取ってみてください。したがって、この場合、戻り値はconstへのconstポインタintです。const戻り値は変更できる左辺値ではないため、ここではポインタ自体を作成しても意味がありません。constただし、指示先を作成すると、呼び出し元がによって返されたint(またはの配列int)を変更できないことが保証されMethod3ます。

const int*const&になるint const*const&ので、これはconstへのconstポインタへの参照intです。参照によるconstポインターの受け渡しも意味がありません-参照された値を変更することはできません。これは、ポインターがconst同じであり、参照とポインターが等しいストレージを占有するため、スペースを節約することもできないためです。

最後constは、メソッドがthisオブジェクトを変更しないことを示しています。thisメソッド本体内のポインターには、(理論的な)宣言がありT const * const thisます。つまり、const T*オブジェクトはを呼び出すことができますT::Method3()


2
これ(およびildjarnの同様の答え)に投票します。これは、最初constのsをフレーズの先頭に置かない方が全体的に意味があるということを部分的に指摘するためです。const言語がそれを許すとしても、そこに置くことは悪い習慣だと私が思う理由はまさにこれであり、それは最も一般的な使用法です。
TEDの

12

のルールを覚える簡単な方法constは、次のように考えることです。constです。左側に何もない場合を除いて、左側にあるものに適用されます。

したがって、の場合const int * const、最初のconstの左側には何もないので、int、2番目の何かがあるため、ポインターに適用されます。

このルールは、あなたが持っている場合に何が起こるかを教えてくれます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

私は「クロック」または「スパイラル」メソッドを使用するのが好きです。ここでは、識別子名(この場合は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へのconstポインターへの参照を取得するconstメソッドは、const intへのconstポインターをMethod3返します。

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

これが役に立てば幸いです!

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.