C++ のクラスの関数宣言における const キーワード

Shikha Chaudhary 2024年2月16日
  1. C++ のクラスの関数宣言における const キーワード
  2. C++ におけるメンバー関数の動作
  3. C++ での const メンバー関数の動作
  4. まとめ
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 を定義します。

この例に関するいくつかの重要な点に注意してください。

  1. 同じ名前のメンバー関数が 2つあります。 唯一の違いは、そのうちの 1つが const メンバー関数であることです。
  2. 2つのオブジェクトがあり、そのうちの 1つは定数オブジェクトです。
  3. どちらのオブジェクトがどの関数を呼び出すかを指定せずに、両方のオブジェクトからメンバ関数 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

今回は、データ メンバ chocolatesmutable 量指定子を使用しているため、以前のようなエラーは発生しません。 これは、メソッドが呼び出された回数を数えたい場合に役立ちます。

これはすべて、C++ の const メンバー関数に関するものです。 あちこちで少し変更を加えて、例を操作すればするほど、より明確になります。

C++ の const について詳しく知りたい場合は、この ドキュメントを参照してください。

まとめ

この記事では、C++ の const メンバー関数の概念について説明しました。 const メンバー関数は、オブジェクトが誤って変更されないことを保証し、const オブジェクトと const オブジェクト以外の両方で使用できます。

ただし、const オブジェクトは const メンバー関数のみを取り消すことができます。 また、データ メンバーで mutable キーワードを使用すると、const メンバー関数の通常の動作を変更でき、通常はカウントの目的で使用されます。

関連記事 - C++ Function