Menu
Coddy logo textTech

[] と () 演算子のオーバーロード

CoddyのC++ジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 45/104。

添字演算子 ([]) を使用すると、クラスを配列のように動作させることができ、要素へのインデックスによるアクセスが可能になります。関数呼び出し演算子 (()) は、オブジェクトを呼び出し可能なエンティティ(ファンクタとして知られています)に変えます。

添字演算子を使用した単純な配列ラッパーを以下に示します:

class IntArray {
    int* data;
    size_t size;
    
public:
    IntArray(size_t s) : size(s), data(new int[s]()) {}
    ~IntArray() { delete[] data; }
    
    int& operator[](size_t index) {
        return data[index];
    }
    
    const int& operator[](size_t index) const {
        return data[index];
    }
};

2つのバージョンを提供していることに注目してください。1つは非const参照を返し(変更が可能)、もう1つのconstバージョンはconstオブジェクトで動作します。これにより、読み取りと書き込みの両方でarr[0] = 5;と記述できるようになります。

関数呼び出し演算子は、関数のように「呼び出す」ことができるオブジェクトを作成します。

class Multiplier {
    int factor;
    
public:
    Multiplier(int f) : factor(f) {}
    
    int operator()(int value) const {
        return value * factor;
    }
};

Multiplier triple(3);
int result = triple(10);    // 30を返します

ファンクタは、通常の関数とは異なり、呼び出し間で状態を維持できるため強力です。これらは、設定値を保持するカスタマイズ可能な動作が必要なSTLアルゴリズムで一般的によく使用されます。

challenge icon

チャレンジ

簡単

添字演算子と関数呼び出し演算子の両方を組み合わせた ScoreTracker クラスを作成しましょう。このクラスはプレイヤーのスコアを保存し、[] を使用してインデックスでアクセスできるようにすると同時に、渡されたスコアにボーナス倍率を適用するファンクタとしても機能します。

コードを整理するために、2つのファイルを作成します。

  • ScoreTracker.h: プレイヤースコアの配列を管理し、ボーナスを適用できる ScoreTracker クラスを定義します。クラスには以下のものを含める必要があります。
    • スコアを保存するための動的に割り当てられた int* 配列
    • スコアの数を保持する size_t メンバ
    • ボーナス倍率を保持する double メンバ
    • サイズとボーナス倍率を受け取り、すべてのスコアを 0 に初期化するコンストラクタ
    • 動的メモリを適切にクリーンアップするデストラクタ
    • インデックスでスコアにアクセスするための 添字演算子 [] (const 版と非 const 版の両方)
    • int のスコアを受け取り、そのスコアにボーナス倍率を掛けた値を (int として) 返す 関数呼び出し演算子 ()
    • スコアの数を返す getSize() メソッド

    非 const の添字演算子は、tracker[0] = 100; のように書き込めるように参照を返します。const 版は、const オブジェクトに対して読み取り専用のアクセスを許可します。関数呼び出し演算子は、オブジェクトの状態を変更しないため、const としてマークする必要があります。

  • main.cpp: 以下の入力を読み取ります (それぞれ別の行にあります)。
    1. プレイヤー数 (サイズ)
    2. ボーナス倍率 (double 型)
    3. 各プレイヤーのスコア (1行に1つ、サイズ分)
    4. ボーナスを適用するテストスコア

    ScoreTracker を作成し、添字演算子を使用して各プレイヤーのスコアを保存してから、すべてのスコアを表示します。最後に、関数呼び出し演算子を使用して、ボーナスが適用されたスコアを計算します。

    出力形式:

    Player 0: <score>
    Player 1: <score>
    ...
    Bonus applied to <test_score>: <result>

例えば、プレイヤーが3人、倍率が 1.5、スコアが 100, 200, 150、テストスコアが 80 の場合:

Player 0: 100
Player 1: 200
Player 2: 150
Bonus applied to 80: 120

入力の変換には std::stoi()std::stod() を使用してください。ヘッダーファイルにはインクルードガードを忘れないでください。

チートシート

添字演算子 [] を使用すると、オブジェクトに配列のようにアクセスできるようになります。関数呼び出し演算子 () は、オブジェクトを関数のように呼び出し可能(ファンクタ)にします。

添字演算子

読み取り/書き込みアクセスのために、const版と非const版の両方を提供します:

class IntArray {
    int* data;
    size_t size;
    
public:
    IntArray(size_t s) : size(s), data(new int[s]()) {}
    ~IntArray() { delete[] data; }
    
    // Non-const version: allows modification
    int& operator[](size_t index) {
        return data[index];
    }
    
    // Const version: read-only access
    const int& operator[](size_t index) const {
        return data[index];
    }
};

関数呼び出し演算子

呼び出し間で状態を保持できるファンクタを作成します:

class Multiplier {
    int factor;
    
public:
    Multiplier(int f) : factor(f) {}
    
    int operator()(int value) const {
        return value * factor;
    }
};

Multiplier triple(3);
int result = triple(10);    // Returns 30

ファンクタは、保存された設定によるカスタマイズ可能な動作が必要なSTLアルゴリズムで役立ちます。

自分で試してみよう

#include <iostream>
#include <string>
#include "ScoreTracker.h"

using namespace std;

// TODO: ScoreTracker のコンストラクタを実装する
ScoreTracker::ScoreTracker(size_t size, double multiplier) {
    // TODO: メンバを初期化し、動的配列を割り当てる
    // すべてのスコアを 0 に初期化する
}

// TODO: ScoreTracker のデストラクタを実装する
ScoreTracker::~ScoreTracker() {
    // TODO: 動的メモリをクリーンアップする
}

// TODO: 非 const 添字演算子を実装する

// TODO: const 添字演算子を実装する

// TODO: 関数呼び出し演算子を実装する

// TODO: getSize メソッドを実装する
size_t ScoreTracker::getSize() const {
    // TODO: スコアの数を返す
}

int main() {
    string line;
    
    // プレイヤーの数を読み込む
    getline(cin, line);
    size_t numPlayers = stoi(line);
    
    // ボーナス倍率を読み込む
    getline(cin, line);
    double multiplier = stod(line);
    
    // TODO: numPlayers と multiplier を使用して ScoreTracker を作成する
    
    // TODO: 各プレイヤーのスコアを読み込み、添字演算子を使用して格納する
    
    // TODO: テストスコアを読み込む
    
    // TODO: すべてのプレイヤースコアを "Player X: <score>" の形式で表示する
    
    // TODO: ボーナス適用結果を "Bonus applied to <test_score>: <result>" の形式で表示する
    
    return 0;
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン