C++ のクラスの関数宣言における const キーワード
C++ では、const
キーワードは、プログラムの実行中に変化せず一定のままである値を定義します。 これは、変数とそれらが保持するデータにとって非常に単純に思えます。
しかし、関数を定数として宣言するにはどうすればよいでしょうか。 この記事では、これらすべての質問とその他の多くの質問に答えますので、読み続けてください!
ここで見ている関数は、クラスに属する関数、つまりメンバー関数であることに注意してください。
C++ のクラスの関数宣言における const
キーワード
実際の議論に入る前に、問題文を正しく理解しましょう。
クラスがデータ メンバーとメンバー関数を持つことができることは既にわかっています。 これらのメンバー関数は通常、次のようにクラス内で宣言されます -
class Demo // class
{
public:
int x;
int showDemo(); // member function declaration
}
ここで、メンバ関数 showDemo()
はクラス Demo
に属しています。 しかし、このようにメンバー関数の最後に const
を追加すると、どういう意味になりますか?
class Demo // class
{
public:
int x;
int showDemo() const; // const member function declaration
}
これを理解するために、まずメンバー関数が C++ で通常どのように動作するかを見てみましょう。
C++ におけるメンバー関数の動作
以下のコードを見てください。 ここでは、まず、値が 2,
に設定されたデータ メンバー chocolates
とメンバー関数 Desert()
を持つ Demo
というクラスを定義します。
メンバー関数内で、welcome ステートメントと共に、データ メンバー chocolates
の元の値を出力し、この値を 1 増やします。 さらに、次のステートメントで chocolates
のインクリメントされた値を出力します。
最後に、オブジェクト demo
を作成し、メンバー関数 Desert()
を main
ブロックから呼び出します。 また、オブジェクト demo
および dot
演算子を使用して、chocolates
の値を出力します。
#include <iostream>
using namespace std;
class Demo {
public:
int chocolates = 2;
public:
void Desert() // member function
{
cout << "Hello Chocolates" << endl;
cout << "Before change: " << chocolates << endl;
chocolates++;
cout << "After change: " << chocolates << endl;
}
};
int main() {
Demo demo;
demo.Desert();
cout << demo.chocolates << endl;
}
出力:
Hello Chocolates
Before change: 2
After change: 3
3
ここで、データ メンバー chocolates
の値をメンバー関数内から変更したことがわかります。 変更をより正確に強調するために、この変数の値も main
ブロックから出力しますが、それでも更新された値である 3
を取得します。
したがって、この例は、通常のメンバー関数を使用してオブジェクトを変更できることを意味します。
ここでは、1つのクラスと 1つのオブジェクトしかありません。 ただし、多くのクラスやオブジェクトを操作していると、誤ってオブジェクトに変更が加えられる可能性が高くなります。
これを回避するために、C++ の const
メンバー関数を使用します。
C++ での const
メンバー関数の動作
以下の例を見てください。 このコードは前のコードと同じですが、今回はメンバー関数の後に const
キーワードを置きます。
#include <iostream>
using namespace std;
class Demo {
public:
int chocolates = 2;
public:
void Desert() const // const member function
{
cout << "Hello Chocolates" << endl;
cout << "Before change: " << chocolates << endl;
chocolates++;
cout << "After change: " << chocolates << endl;
}
};
int main() {
Demo demo;
demo.Desert();
cout << demo.chocolates << endl;
}
出力:
In member function 'void Demo::Desert() const':
error: increment of member 'Demo::chocolates' in read-only object
13 | chocolates++;
| ^~~~~~~~~~
メンバー関数を定数にすることで、出力がどのように変化するかを確認できます。 今度は、chocolates
の値がインクリメントされず、エラーが発生します。
したがって、この例は、const
メンバー関数を使用してオブジェクトを変更できないことを意味します。
上記の 2つのメンバー関数の比較により、そのような関数宣言での const
の使用は、どのクラス メンバーにも変更がないことを意味すると結論付けます。 const
をメソッドに追加すると、this
ポインターは const
オブジェクトを指すため、データ メンバーを変更することはできません。
以上のことを学んだ後、オブジェクトの変更を避けるために const
メンバー関数を使用すると言えます。 しかし、次のように疑問に思うかもしれません: const
オブジェクトの用途は何ですか?
オブジェクトを const
として宣言すると、const
メンバー関数のみを呼び出すことができます。 これは、const
オブジェクトを変更できないためであり、この非変更は const
メンバー関数によってのみ約束されます。
以下の例を見てください。
Desert
クラス内には、desert()
と desert() const
という 2つのメンバー関数があります。 次に、main
ブロック内で、2つのオブジェクト d
と定数オブジェクト dd
を定義します。
この例に関するいくつかの重要な点に注意してください。
- 同じ名前のメンバー関数が 2つあります。 唯一の違いは、そのうちの 1つが
const
メンバー関数であることです。 - 2つのオブジェクトがあり、そのうちの 1つは定数オブジェクトです。
- どちらのオブジェクトがどの関数を呼び出すかを指定せずに、両方のオブジェクトからメンバ関数
desert()
を呼び出します。
#include <iostream>
using namespace std;
class Desert {
private:
int cakes;
public:
void desert() { cout << "The first desert function." << endl; }
void desert() const // the const member function
{
cout << "The second const desert function." << endl;
}
};
int main() {
Desert d; // object of class
const Desert& dd = d; // constant object of class
d.desert();
dd.desert();
}
出力:
The first desert function.
The second const desert function.
出力は、通常のメンバー関数 desert()
が通常のオブジェクト d
によって自動的に呼び出されたことを明確に示しています。 一方、const
メンバー関数 desert() const
は、const
オブジェクト dd
によって自動的に呼び出されます。
オブジェクトから const
キーワードを削除すると、出力が変わります。
int main() {
Desert d; // object of class
Desert& dd = d; // remove the constant keyword
d.desert();
dd.desert();
}
出力:
The first desert function.
The first desert function.
今回は両方のオブジェクトが最初の関数を呼び出します。 これは、const
オブジェクトが const
メンバー関数を呼び出すことを証明しています。
これは、非定数オブジェクトで const
メンバー関数を呼び出せないという意味ではないことに注意してください。 ただし、非 const
関数は、非 const
オブジェクトによってのみ呼び出すことができます。
ここまでは順調ですが、例外的なケースがあります。 mutable
量指定子をクラスのデータ メンバーと一緒に使用すると、const
メソッドでもオブジェクトを変更できます。
この例を見てください。
#include <iostream>
using namespace std;
class Demo {
public:
mutable int chocolates = 2; // mutable quantifier
public:
void Desert() const // const member function
{
cout << "Hello Chocolates" << endl;
cout << "Before change: " << chocolates << endl;
chocolates++;
cout << "After change: " << chocolates << endl;
}
};
int main() {
Demo demo;
demo.Desert();
cout << demo.chocolates << endl;
}
出力:
Hello Chocolates
Before change: 2
After change: 3
3
今回は、データ メンバ chocolates
で mutable
量指定子を使用しているため、以前のようなエラーは発生しません。 これは、メソッドが呼び出された回数を数えたい場合に役立ちます。
これはすべて、C++ の const
メンバー関数に関するものです。 あちこちで少し変更を加えて、例を操作すればするほど、より明確になります。
C++ の const
について詳しく知りたい場合は、この ドキュメントを参照してください。
まとめ
この記事では、C++ の const
メンバー関数の概念について説明しました。 const
メンバー関数は、オブジェクトが誤って変更されないことを保証し、const
オブジェクトと const
オブジェクト以外の両方で使用できます。
ただし、const
オブジェクトは const
メンバー関数のみを取り消すことができます。 また、データ メンバーで mutable キーワードを使用すると、const
メンバー関数の通常の動作を変更でき、通常はカウントの目的で使用されます。