C++
 Computer >> コンピューター >  >> プログラミング >> C++

C++における関数オーバーロードとconstキーワードの挙動

C++では関数のオーバーロード(多重定義)が可能です。その中には通常のメンバ関数もあれば、const修飾された定数メンバ関数もあります。本記事では、サンプルプログラムとその実行結果をもとに、定数メンバ関数と通常の関数の違い、そしてオーバーロード時の注意点を解説します。

constメンバ関数と通常の関数のオーバーロード

まず、同じ名前の関数を「const版」と「非const版」でオーバーロードした例を見てみましょう。

#include <iostream>
using namespace std;
class my_class {
    public:
        void my_func() const {
            cout << "Calling the constant function" << endl;
        }
        void my_func() {
            cout << "Calling the normal function" << endl;
        }
};
int main() {
    my_class obj;
    const my_class obj_c;
    obj.my_func();
    obj_c.my_func();
}

実行結果

Calling the normal function
Calling the constant function

この結果から、次のことがわかります。

  • オブジェクトが通常のオブジェクトである場合 → 通常のメンバ関数が呼び出される
  • オブジェクトがconstオブジェクトである場合 → constメンバ関数が呼び出される

つまり、C++コンパイラはオブジェクト自体がconstかどうかを判断材料として、適切なオーバーロードを選択しているのです。

値渡しの引数でconstを使ったオーバーロードはエラーになる

一方、オーバーロードされた2つの関数が引数を持ち、その片方だけがconst修飾されている場合、値渡し(pass by value)ではコンパイルエラーになります。

#include <iostream>
using namespace std;
class my_class {
    public:
        void my_func(const int x) {
            cout << "Calling the function with constant x" << endl;
        }
        void my_func(int x){
            cout << "Calling the function with x" << endl;
        }
};
int main() {
    my_class obj;
    obj.my_func(10);
}

実行結果(コンパイルエラー)

[Error] 'void my_class::my_func(int)' cannot be overloaded
[Error] with 'void my_class::my_func(int)'

これは、値渡しの場合、仮引数のconst有無が関数のシグネチャ(識別情報)に含まれないためです。呼び出し側にとって両者は同一の関数に見えるため、コンパイラはこれらを区別できず、オーバーロードとして認められません。

ポインタや参照型ならオーバーロード可能

ただし、引数がポインタ型や参照型の場合は話が変わります。const int*int*は異なる型として扱われるため、問題なくオーバーロードできます。

#include <iostream>
using namespace std;
class my_class {
    public:
        void my_func(const int *x) {
            cout << "Calling the function with constant x" << endl;
        }
        void my_func(int *x) {
            cout << "Calling the function with x" << endl;
        }
};
int main() {
    my_class obj;
    int x = 10;
    obj.my_func(&x);
}

実行結果

Calling the function with x

この例では、&xint*型であるため、非const版のmy_func(int*)が呼び出されています。もしconst intへのポインタを渡せば、const版が選択されます。

まとめ

  • メンバ関数のconst有無はオーバーロードの区別に使える。constオブジェクトからはconstメンバ関数が、非constオブジェクトからは通常のメンバ関数が呼ばれる。
  • 値渡しの引数に対するconstの有無はシグネチャに影響しないため、それだけでオーバーロードするとコンパイルエラーになる。
  • ポインタや参照を引数にする場合は、constの有無で型が異なるため、正常にオーバーロードできる。
  1. PHPの関数オーバーロードとオーバーライドの違いを徹底解説

    PHPにおける関数のオーバーロード(Overloading) 関数のオーバーロードとは、同じ名前のメソッドを複数定義し、受け取る引数の数や型に応じて異なる処理を実行できるようにする仕組みです。JavaやC++などの言語では言語仕様としてサポートされていますが、PHPでは従来型のオーバーロードは直接サポートされていません。そこで、マジックメソッドの__call()を利用することで、引数の個数に応じて処理を切り替える、いわゆるオーバーロードのような動作を実現できます。 サンプルコード <?php class Shape { const PI = 3.142; functi

  2. C#におけるreadonlyキーワードとconstキーワードの違いを徹底解説

    readonlyキーワードとはreadonlyキーワードは、宣言時またはコンストラクター内で一度だけ値を代入できる変数(読み取り専用フィールド)を定義するために使用します。一方、constキーワードは、プログラム全体で使用する定数を定義するために使用します。両者は似たような用途で使われますが、動作や制約に重要な違いがあります。以下に、C#におけるreadonlyとconstの基本的な使用例を示します。コード例using System.IO; using System; public class Program { public const int VALUE = 10; pu