【C++】オーバーロード入門 | 関数と演算子を多重定義する方法

目次

はじめに

C++では、同じスコープ内に、同じ名前の関数や演算子を複数定義することができます。これを**オーバーロード(多重定義)**と呼びます。コンパイラは、渡された引数の型や個数(シグネチャ)を元に、どのバージョンを呼び出すべきかを自動的に判断してくれます。

オーバーロードは、オブジェクト指向の**多態性(ポリモーフィズム)**を静的に実現する仕組みであり、コードの直感性と可読性を大きく向上させます。

この記事では、関数オーバーロードと、自作クラスを組み込み型のように扱えるようにする演算子オーバーロードの基本を網羅的に解説します。


1. 関数オーバーロード

同じ名前で、引数の型や個数が異なる関数を複数定義することです。

#include <iostream>

// int型を2倍にする
int double_value(int n) {
    return n * 2;
}
// double型を2倍にする
double double_value(double n) {
    return n * 2.0;
}

int main() {
    std::cout << double_value(10) << std::endl;      // int版が呼ばれる
    std::cout << double_value(5.5) << std::endl;     // double版が呼ばれる
    return 0;
}

2. 算術演算子のオーバーロード

+, -, *, /, += などの算術演算子を、自作のクラスで使えるように定義します。

サンプルコード

#include <iostream>

struct Vector2D {
    int x, y;

    // メンバ関数として += をオーバーロード
    Vector2D& operator+=(const Vector2D& rhs) {
        this->x += rhs.x;
        this->y += rhs.y;
        return *this;
    }
};

// グローバル関数として + をオーバーロード
Vector2D operator+(Vector2D lhs, const Vector2D& rhs) {
    lhs += rhs; // 実装は += を再利用するのが定石
    return lhs;
}

int main() {
    Vector2D v1{1, 2}, v2{3, 4};
    Vector2D v3 = v1 + v2; // operator+ が呼ばれる
    std::cout << "v3: (" << v3.x << ", " << v3.y << ")" << std::endl; // -> (4, 6)
    return 0;
}

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

==, !=, <, > などをオーバーロードすることで、自作クラスのオブジェクト同士を比較できるようになります。

サンプルコード (C++20以前)

struct Product {
    int id;
};

// == と < を定義すれば、他はこれらを元に実装できる
bool operator==(const Product& a, const Product& b) { return a.id == b.id; }
bool operator<(const Product& a, const Product& b) { return a.id < b.id; }
bool operator!=(const Product& a, const Product& b) { return !(a == b); }
bool operator>(const Product& a, const Product& b) { return b < a; }
// ... <=, >= も同様

宇宙船演算子 <=> (C++20)

C++20では、宇宙船演算子 (<=>) を一つ定義するだけで、コンパイラが他の全ての比較演算子 (==, !=, <, >, <=, >=) を自動的に生成してくれます。

#include <compare> // three-way comparison

struct Product {
    int id;
    // <=>をデフォルト実装するだけで、全ての比較演算子が利用可能になる
    auto operator<=>(const Product& other) const = default;
};

int main() {
    Product p1{10}, p2{20};
    if (p1 < p2) { /* 比較可能 */ }
    return 0;
}

4. その他の便利な演算子オーバーロード

添字演算子 []

オブジェクトを配列のように扱えるようにします。

#include <vector>

class MyData {
public:
    std::vector<int> data = {10, 20, 30};
    // 戻り値を参照(&)にすると、値の書き換えも可能になる
    int& operator[](int index) {
        return data[index];
    }
};

int main() {
    MyData d;
    std::cout << d[1] << std::endl; // -> 20
    d[1] = 99; // 値を書き換える
    std::cout << d[1] << std::endl; // -> 99
    return 0;
}

関数呼び出し演算子 ()

オブジェクトを関数のように呼び出せるようにします(関数オブジェクトまたはファンクタ)。

C++

#include <iostream>

struct Adder {
    int operator()(int a, int b) const {
        return a + b;
    }
};

int main() {
    Adder add;
    int result = add(3, 4); // オブジェクトを関数として呼び出す
    std::cout << result << std::endl; // -> 7
    return 0;
}

まとめ

今回は、C++のオーバーロード機能について、関数と各種演算子を例に解説しました。演算子オーバーロードを適切に使うことで、自作したクラスを、intなどの組み込み型と全く同じような、直感的で自然な構文で扱えるようになり、コードの可読性を劇的に向上させることができます。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

私が勉強したこと、実践したこと、してることを書いているブログです。
主に資産運用について書いていたのですが、
最近はプログラミングに興味があるので、今はそればっかりです。

目次