C++で書かれたチュートリアルとコードを読むとき、私はよくconst
キーワードにつまずきます。
次のように使用されていることがわかります。
const int x = 5;
これは、x
が定数変数であり、おそらく読み取り専用メモリに格納されることを意味することを知っています。
しかし、何ですか
void myfunc( const char x );
そして
int myfunc( ) const;
?
void myfunc(const char x);
これは、パラメータx
が関数内で値を変更できないcharであることを意味します。例えば:
void myfunc(const char x)
{
char y = x; // OK
x = y; // failure - x is `const`
}
最後の1つ:
int myfunc() const;
これはクラス宣言内にない限り違法です-const
メンバー関数はクラスメンバーの変更を禁止します-const
非メンバー関数は使用できません。この場合、定義は次のようになります。
int myclass::myfunc() const
{
// do stuff that leaves members unchanged
}
const
メンバー関数で変更可能にする必要がある特定のクラスメンバーがある場合は、mutable
として宣言できます。例はメンバーlock_guard
は、クラスのconst
および非const
メンバー関数をスレッドセーフにしますが、must自身の内部操作中に変更します。
最初の関数の例は多かれ少なかれ無意味です。より興味深いものは次のとおりです。
_void myfunc( const char *x );
_
これは、コンパイラに_*x
_のcontentsが変更されないことを伝えます。つまり、myfunc()
内では次のようなことはできません。
_strcpy(x, "foo");
_
C++メンバー関数の2番目の例は、呼び出しによってオブジェクトの内容が変更されないことを意味します。
与えられた:
_class {
int x;
void myfunc() const;
}
_
someobj.myfunc()
は次のような変更を許可されていません。
_x = 3;
_
この:
void myfunc( const char x );
関数内でx
を変更できないことを意味します。つまり、これは違法です。
void myfunc( const char x ) {
x = ...;
}
一方:
int myfunc() const;
myfunc()がクラス内のメソッドである場合にのみ意味があります。基本的に、メソッドはクラスインスタンスを変更できないことを意味します(つまり、instance.myfunc()を呼び出す前後のインスタンスの状態は同じになります)。
変数識別子の前のconst
は、変数を初期化でき、その後は変更できないことを示します。
クラスメソッド名の後、const
は、メソッドがクラスの観測可能な状態を変更しないことを示します。 mutable
キーワードを使用すると、内部データを変更できます。
ポインターまたは参照変数の前のconst
は、参照されたデータを変更するために識別子が使用されないことを示しますが、他の方法で変更される場合があります。
const int *pInt = &x;
Constは、ポインター自体を変更できないことを示すためにも使用できます。
int * const pInt = &x;
私は非常に良い説明を見つけました: http://duramecho.com/ComputerInformation/WhyHowCppConst.html
基本的にすべての混乱は、キーワードconst
のさまざまなユースケースにあります。 const
を配置する場所に応じて、何かが不変であるべきか、何かが他の何かを変更できないようにすべきであると言います。 「何か」は、変数、ポインター、または関数/メソッドである可能性がありますが、オブジェクトの関数またはメンバー変数に渡される変数の値を変更できないようにする必要があります。
const
修飾子は、const
として定義された変数/ポインターがプログラムによって変更されず、明示的な初期化またはハードウェア依存の手段から値を受け取ることを意味します。
パラメーター宣言でconst
として定義されているポインターは、関数コードが指すものを変更しません。基本的に、ポインタを使用でき、それはほとんど「読み取り専用」として機能します。
例えば:-
void foo(const char *x)
{
while(*x)
{
if(*x==' ') cout << '-'; //printing - when a space is encountered
else cout << *x;
x++;
}
}
上記の機能は問題なく、エラーは表示されません。ただし、fooに渡された文字列を変更できるものがある場合。スペースを$に置き換える関数を言う。 $を印刷せず、$に変更します。このようなもの:-
void foo(const char *x)
{
while(*x)
{
if(*x==' ') *x = '$'; //printing - when a space is encountered
else cout << *x;
x++;
}
}
コンパイルされません。つまり、読み取り専用メモリの場所への割り当てエラー。
2つの違いは、最初の型がvoid(char)
型であり、2番目の型がint()const
型であることです。
末尾にconst
を持つそのような型を持つ関数は、クラスのメンバー関数にしかなれません。これは、メンバー関数がクラス値(this
が参照するもの)を変更しないことを意味します)クラス外から見たとき。コンパイラーはそれをある程度チェックし、constメンバー関数のクラスメンバーに直接書き込むとコンパイル時エラーが発生し、関数はconstメンバー関数のみを直接呼び出すことができます(特別なディレクティブが存在するため、メンバが書き込むコンパイラは、外部から見たクラスの値を変更しません。これは、mutable
キーワードによって行われます)。
提示した関数には、char const
型のパラメーターがありました。そのようなパラメーターは、その関数内では変更できません。ただし、関数の型には影響せず、関数の呼び出し元には影響しません。
void myfunc(const char x)
は、あなたの例の_const int x = 5
_と非常に似ています:関数myfunc
内でローカルに利用可能な定数を宣言します。定数なので、その値は変更できません。
int myfunc() const
は、クラスのメンバー関数です。 const
は、関数が実行されるクラスのインスタンスを関数が変更しないことを示します。そのため、関数内では、_this->foo = 7
_のようなことをしたり、constではない他の関数を呼び出したりすることはできません。