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

C++における配列インデックス演算子[]のオーバーロード方法を徹底解説

C++における演算子のオーバーロードは、オブジェクト指向プログラミングの重要な機能の一つです。演算子オーバーロードは、コンパイル時ポリモーフィズム(静的ポリモーフィズム)に分類されます。本記事では、その代表例として、配列インデックス演算子 [] のオーバーロードを実装し、独自クラスでも配列のように要素へアクセスできるようにする方法を解説します。

配列インデックス演算子[]をオーバーロードするメリット

通常、クラス内部で管理している配列に対して [] 演算子を使うと、範囲外アクセスが発生してもコンパイラは検出してくれません。operator[] をオーバーロードすれば、以下のようなメリットがあります。

  • インデックスが有効な範囲内かどうかを実行時にチェックできる(境界チェック)
  • 組み込み配列と同じ直感的な構文でクラスの要素にアクセスできる
  • 戻り値を参照型(int&)にすることで、読み取りだけでなく書き込みも可能になる

アルゴリズム

1. 配列サイズを定義したクラス Arr を作成する。
2. コンストラクタ内で for ループを使い、全要素を指定した値で初期化する。
3. オーバーロードされた operator[] で全要素を出力する。

サンプルコード

以下のコードでは、クラス Arr 内部の配列 A[] へのアクセスを operator[] 経由で行い、不正なインデックスが指定された場合にはエラーメッセージを表示してプログラムを終了します。

#include <iostream>
#include <stdlib.h>
using namespace std;

const int M = 7;

class Arr {
private:
    int A[M];
    int size;
public:
    // コンストラクタ:サイズと初期値を受け取る
    Arr(int s, int v) {
        if(s > M) {
            cout << endl << "最大サイズを超えています";
            exit(1);
        }
        size = s;
        for(int i = 0; i < size; i++)
            A[i] = v;
    }

    // インデックス演算子のオーバーロード(境界チェック付き)
    int& operator[](int i) {
        if((i < 0) || (i >= size)) {
            cout << endl << "エラー: 配列の範囲外アクセスです";
            exit(1);
        }
        return A[i];
    }
};

int main() {
    int i = 0;
    Arr a(7, 0);

    // 書き込み:operator[] の戻り値(参照)に代入
    for(i = 0; i < 7; i++)
        a[i] = i * 10;

    cout << "配列の要素:" << endl;

    // 読み取り
    for(i = 0; i < 7; i++) {
        int val = a[i];
        cout << val << endl;
    }
    return 0;
}

実行結果

配列の要素:
0
10
20
30
40
50
60

コードのポイント解説

  • 戻り値を int&(参照)にしている点が重要です。参照を返すことで a[i] = i * 10; のように代入による書き込みが可能になります。値渡しにすると書き込みはできません。
  • operator[] の内部では、引数 i0 以上 size 未満 の範囲にあるかを確認し、範囲外なら「配列の範囲外アクセス」のエラーを出して終了します。これにより安全性が向上します。
  • 実際の開発では、例外処理(std::out_of_range を throw するなど)や const 版の operator[] を併せて用意すると、より堅牢な設計になります。

まとめ

[] 演算子のオーバーロードを使えば、自作クラスを組み込み配列と同じ感覚で操作できるようになり、同時に境界チェックなどの安全機構も組み込めます。C++の静的ポリモーフィズムを活かしたこのテクニックは、独自のコンテナクラスを作成する際にぜひ覚えておきたい基本技です。

  1. 【C++入門】配列を関数に渡す3つの方法をわかりやすく解説

    C++では、配列全体をそのまま関数の引数として渡すことはできません。しかし、インデックスを付けずに配列名を指定することで、配列へのポインタを渡すことができます。これは「配列名は先頭要素へのポインタに読み替えられる(配列の減衰)」というC++の仕組みによるものです。1次元配列を関数の引数として渡したい場合は、以下の3つのいずれかの方法で関数の仮引数を宣言します。どの方法でも、コンパイラに対して「整数型のポインタを受け取る」という情報が伝わるため、動作結果はすべて同じになります。配列を関数に渡す3つの宣言方法1. ポインタとして仮引数を宣言するvoid myFunction(int *param)

  2. C++における単項演算子のオーバーロード方法を徹底解説

    C++では、operatorキーワードを使って関数を宣言することで、クラスのインスタンスに適用した際の演算子の意味を独自に定義できます。これにより、1つの演算子に複数の意味を持たせることができ、これを「オーバーロード」と呼びます。コンパイラは、オペランドの型を調べることで、どの定義を適用すべきかを判断します。 単項演算子とは 単項演算子は、1つのオペランドに対してのみ作用する演算子です。代表的な単項演算子には以下のようなものがあります。 インクリメント(++)およびデクリメント(--)演算子 単項マイナス(-)演算子 論理NOT(!)演算子 単項演算子は、それが呼び出されたオブジェクトその