C++における演算子オーバーロードの実装テクニック

演算子オーバーロードの基本概念

演算子オーバーロードとは、組み込み型に対して定義されている演算子を、ユーザ定義型に対しても適用可能にする仕組みです。これにより、クラスオブジェクトに対して直感的な算術記法を使用できます。

一般的な形式は以下の通りです:

戻り値の型 operator 演算子記号 (引数リスト)

単項演算子のオーバーロード

前置インクリメント演算子の実装

前置++演算子をオーバーロードする例です。メンバ変数を直接変更し、変更後のオブジェクトを返します。

class Counter {
public:
    int value;
    
    Counter(int init) : value(init) {}
    
    Counter operator++() {
        ++value;
        return Counter(value);
    }
};

int main() {
    Counter c(5);
    ++c;
    std::cout << c.value;  // 出力: 6
    return 0;
}

符号反転演算子の実装

単項マイナス演算子をオーバーロードし、新しいオブジェクトを生成して返します。

class SignedValue {
public:
    int data;
    
    explicit SignedValue(int v) : data(v) {}
    
    SignedValue operator-() const {
        return SignedValue(-data);
    }
};

int main() {
    SignedValue sv(7);
    SignedValue neg = -sv;
    std::cout << neg.data;  // 出力: -7
    return 0;
}

二項演算子のオーバーロード

加算演算子をオーバーロードして、同じクラスのインスタンス同士の足し算を可能にします。

class Point {
public:
    int x;
    
    Point(int coord) : x(coord) {}
    
    Point operator+(const Point& other) const {
        return Point(x + other.x);
    }
};

int main() {
    Point p1(10), p2(20);
    Point sum = p1 + p2;
    std::cout << sum.x;  // 出力: 30
    return 0;
}

比較演算子のオーバーロード

構造体に対して大小関係を定義します。structでもclassと同様に演算子オーバーロードが可能です。

struct Score {
    int points;
    
    bool operator<(const Score& rhs) const {
        return points < rhs.points;
    }
};

入出力ストリーム演算子のオーバーロード

istreamおよびostreamとの連携を実現します。friend宣言により、プライベートメンバへのアクセスを許可します。

class Record {
public:
    int id;
    int score;
    
    friend std::ostream& operator<<(std::ostream& out, const Record& r) {
        out << r.id << " " << r.score;
        return out;
    }
    
    friend std::istream& operator>>(std::istream& in, Record& r) {
        in >> r.id >> r.score;
        return in;
    }
};

int main() {
    Record rec;
    std::cin >> rec;
    std::cout << rec;
    return 0;
}

代入演算子のオーバーロード

オブジェクト間の深いコピーを制御します。自己代入のチェックや動的メモリ管理が必要な場合は、より堅牢な実装が求められます。

class Vector2D {
public:
    int u, v;
    
    Vector2D(int x, int y) : u(x), v(y) {}
    
    Vector2D& operator=(const Vector2D& src) {
        if (this != &src) {
            u = src.u;
            v = src.v;
        }
        return *this;
    }
};

int main() {
    Vector2D vecA(1, 2), vecB(3, 4);
    vecA = vecB;
    std::cout << vecA.u << " " << vecA.v;  // 出力: 3 4
    return 0;
}

添字演算子のオーバーロード

配列のようなインターフェースを提供します。境界チェックや読み取り専用アクセスの実装も検討すべきです。

class Buffer {
public:
    int x, y;
    int storage[100];
    
    Buffer(int initX, int initY) : x(initX), y(initY) {}
    
    int& operator[](size_t idx) {
        return storage[idx];
    }
    
    const int& operator[](size_t idx) const {
        return storage[idx];
    }
};

int main() {
    Buffer buf(0, 0);
    buf[50] = 999;
    std::cout << buf[50];  // 出力: 999
    return 0;
}

タグ: C++ 演算子オーバーロード オブジェクト指向 STL istream

8月22日 20:57 投稿