C++によるプログラミング入門補足5
演算子のオーバーロードについて

 こんにちは。今回は代入演算子のオーバーロード(多重定義)をやってみましょう。


 代入演算子のオーバーロードは、実は「コピーコンストラクタ、代入演算子」のところですでにやっていました。つまり、「=」という演算子はC++で定義されている演算子ですが、自分のクラス用に、定義し直したのが、「演算子=のオーバーロード」なのです。

 演算子も実は特別な形をした関数です。ということは、演算子にもクラスのメンバであるのものとそうでないものがあります。代入演算子はクラスのメンバ関数の例です。
 それで、ここでは、メンバでない演算子の例を見ましょう。毎度のことですが、「○○とは、そもそも、、、」なんて説明を読んだり考えたりするより、下の具体例を見て、そんなものかと理解してください。

 では、まず、下のようなクラスを考えたとしましょう。何のことはない、整数を二つデータに持つクラスです。

class Thing
{
    int data1;
    int data2;
public:
    Thing() : data1(0), data2(0){}
    Thing(int d1, int d2) : data1(d1), data2(d2){}
    int get_data1() const{ return data1; }
    void set_data1(int d){ data1=d; }
    int get_data2() const { return data2; }
    void set_data2(int d){ data2=d; }
};

 本論とあまり関係ないですが、コンストラクタが二つあるのはよいですよね。ひとつは、引数なしのコンストラクタです。これは、引数を与えないと、data1もdata2も0になってしまうという定義です。もちろん、引数付きのコンストラクタは、それぞれdata1とdata2を初期化するものです。
 さて、このクラスのオブジェクト(インスタンス)同士の足し算をしたくなったとします。「足し算」とは、二つのデータのそれぞれの足し算としましょう。つまり、

Thing x(10,20), y(30,40);
Thing z = x + y;

 これは、Thing同士を足して、新たなThingを作るということです。こういうことが必要な場合もあるでしょう。これをするには、

Thing operator+(Thing a, Thing b)

というものを定義すればよいのです。
 「なんだ、こりゃ?」が、最初にこれを見たときの、私の反応でした。(ただし、代入演算子のとき、同じ系統のものを見ていますよね。)はじめて見るとなんだかわかりません。実際は、わかるとかわからないの問題ではなく、「こうすればよい」ということなんです。
 一応、それらしく説明すると、はじめにあるThingは、足し算の結果がThingになるという意味です。(よりC++らしく言うと、足し算の結果戻される値の型はThingということです。)aとbは関数の仮引数です。上のような関数を定義すると、それが、

Thing x(10,20), y(30,40);
Thing z = x + y;

の「x + y」などで呼び出されるのです。このとき、aにxが、bにyがコピーされ、関数の定義内で使われます。

 ここまでの説明ですっきりするはずはありません。むしろ、以下の実際のコードを実行して、よくよく眺めてみてください。そうすれば、わかると思います。^^;)

//op_sample0.cpp
#include <iostream>
using namespace std;

class Thing
{
    int data1;
    int data2;
public:
    Thing() : data1(0), data2(0){}
    Thing(int d1, int d2) : data1(d1), data2(d2){}
    int get_data1() const{ return data1; }
    void set_data1(int d){ data1=d; }
    int get_data2() const { return data2; }
    void set_data2(int d){ data2=d; }
};

Thing operator+(Thing a, Thing b){
    //aとbのデータを足しあわせたThingを作る
    Thing temp(a.get_data1() + b.get_data1(), a.get_data2() + b.get_data2());
    //できたThingを戻す
    return temp;
}


int main()
{
    Thing x(10,20), y(30,40);

    Thing a = x + y;
    cout << a.get_data1() << endl;
    cout << a.get_data2() << endl;
}

 つまり、こういうものなんです。

 ところで、上の定義では、引数を仮引数にコピーしていますが、参照を使った

Thing operator+(Thing& a, Thing& b)

の方が、効率が良さそうです。これで、コピーの手間が省けるからです。しかし、aやbのデータを変更するつもりがないので、

Thing operator+(const Thing& a, const Thing& b)

とするべきです。(特別な理由がない限り、constをつけるようにしましょう。)結局、より効率のよいオーバーロードは次のようになります。

Thing operator+(const Thing& a, const Thing& b){
    //aとbのデータを足しあわせたThingを作る
    Thing temp(a.get_data1() + b.get_data1(), a.get_data2() + b.get_data2());
    //できたThingを戻す
    return temp;
}


目次のページ