Awesome Hacks!

プログラミング初心者なので地道に勉強していきます。分からない人の立場から整理していきます。

クラスの応用_演算子のオーバーロード

int型の計算で、

int a;
a = 1 + 2;

と「+」をつかって2つの整数を足すことができる。
 


作成したクラスでもint型のように2つのオペランドについて
演算できるようにしたい。
 
例えば社員数と資本金をメンバに持つ会社クラスを使って、
二つの会社(オブジェクト)を作ったとします。
この会社を合併して新しい会社を設立したい!!
 
【プログラムのイメージ】

    Corp mac(100,2000);
    Corp win(50,1000);

    Corp tama = mac + win;
    tama.disp();

 
【実行結果のイメージ】

$ testOperator.cpp
社員数 150人、資本金 3000万円です。
$

※このプログラムはフィクションです。実在の人物や団体とは関係ありません。
 
こんな感じでしょうか。
 
こんな関数があったらどうにかなりそう。
これをこうやって・・・

//    Corp tama = mac + win;
    Corp tama = mac.sum(win);


こうして・・・

Corp sum(Corp c){
    Corp obj;
    obj.members = 呼び元のmacオブジェクト自身のmembers + winオブジェクト自身のmembers
    obj.money = macオブジェクト自身のmoney + winオブジェクト自身のmoney
    return obj;
}


さっきのところに戻ってみて確認

//    Corp tama = mac + win;
    Corp tama = mac.sum(win);
                         ↑ ここにはCorp型のオブジェクトobjが返ってくるので、それをtamaにコピー

 
これでいけそうですね。
 
しかし、「+」を使いたいわけです。
でも「+」は整数どうしの計算にも使っているので、それを横取りするわけにもいかないし・・・。
 
そうです、オーバーロードします。
引数がCorpの時は自分が実装した本来の処理とは異なる処理を行うように。
 
長々と回りくどくなってきましたので、この辺にして実際の実装を見てみます。
 
【プログラム例】

#include <iostream>
#include <string>

using namespace std;

class Corp {
	private:
		int members;
		int money;
	public:
		Corp(int mem = 0, int mon = 0) :	// デフォルトコンストラクタにしておかないと・・・
				members(mem), money(mon){}
		Corp operator+(Corp c){
			Corp sum;						// 関数内の処理に使う一時的なオブジェクトsumに引数が必要になってしまう。
			sum.members = members + c.members;
			sum.money = money + c.money;
			return sum;
		}
		void disp(){
			cout << "社員数 " << members << "人、資本金" << money << "万円です。" << endl;
		}
};

int main(){
	Corp mac(100,2000);
	Corp win(50,1000);
	cout << "起業しました。\n" << endl;

	cout << "mac株式会社は・・・" << endl;
	mac.disp();
	cout << "win株式会社は・・・" << endl;
	win.disp();

	Corp tama = mac + win;
	cout << "合併しました。\n" << endl;

	cout << "合併後のtama株式会社は・・・" << endl;
	tama.disp();
	return 0;
}


【実行結果】

起業しました。

mac株式会社は・・・
社員数 100人、資本金2000万円です。
win株式会社は・・・
社員数 50人、資本金1000万円です。
合併しました。

合併後のtama株式会社は・・・
社員数 150人、資本金3000万円です。


これを見てみると分かりますが、
A = B + C;
に使われる「+」のような演算子オーバーロードする際はちょっと普通の関数とは異なります。
 
「operator+」という関数名で定義してやればいいわけですね。
「operator+」という関数を引数や戻り値を意識して自分で実装する、使う時は普通の関数とはちょっと違う、それだけで、後はそこまで難しいことではない(はず)です。
 
自分で「-」演算子を作ってみると面白いかもしれない。
例えば、
「リストラ社員数30人、損失額700万円のCorpクラスのfukeikiオブジェクトを作り、自分で実装した「-」オブジェクトを使って引き算してみる」とか・・・。
 

左辺が自分のクラスじゃない場合

はい、次に疑問になるのは、左辺がCorpクラスでない場合です。
特に、Corpでない場合、Corpクラスのメンバ関数にはできません。
でもCorpクラスのprivateな変数にアクセスしたい。
例えば、「好景気が来たので社員数も資本金も100ずつ増えました」というときに、

    tama = 100 + tama;

このように使いたいわけです。
 
そんな時はフレンド関数を作成します。
要は、Corpクラスにfriend指定して「operator+」関数の宣言だけしておき、
あとは、Corpクラスではないので、Corpクラスの外に定義します。
 
【イメージ】

class Corp{
    public:
        friend Corp operator+(int plus, Corp c);      // 宣言
};

Corp operator+(int plus, Corp c){                       // 定義
    Corp p;                     
    p.members = c.members + plus;
    p.money = c.money + plus;
    return p;
}

ここで一つ、重要なのは「左辺の値を第一引数で受け取る」ということ。
 
これを踏まえて・・・
【プログラム例】

#include <iostream>
#include <string>

using namespace std;

class Corp {
	private:
		int members;
		int money;
	public:
		Corp(int mem = 0, int mon = 0) :
				members(mem), money(mon){}
		friend Corp operator+(int plus, Corp c);
		void disp(){
			cout << "社員数 " << members << "人、資本金" << money << "万円です。" << endl;
		}
};

Corp operator+(int plus, Corp c){
	Corp p;	
	p.members = c.members + plus;
	p.money = c.money + plus;
	return p;
}

int main(){
	Corp mac(100,2000);
	cout << "起業しました。\n" << endl;

	cout << "mac株式会社は・・・" << endl;
	mac.disp();

	mac = 100 + mac;
	cout << "好景気になって、社員数も資本金も100増えました!!\n" << endl;

	cout << "現在のmac株式会社は・・・" << endl;
	mac.disp();

	return 0;
}


【実行結果】

起業しました。

mac株式会社は・・・
社員数 100人、資本金2000万円です。
好景気になって、社員数も資本金も100増えました!!

現在のmac株式会社は・・・
社員数 200人、資本金2100万円です。



今回のように左辺と右辺で2つのオペランドを持つ場合(2項演算子)とは違って、
一つしかオペランドを持たないことがある(単項演算子)。
これについての説明は割愛する。
※なお、問題集には取り込んでいる。(クラスの応用1 - Awesome Hacks!
 
以上。