トランプのゲームを作ろうと思うと、カードの番号を加算したりしなければならないケースがあります。
例えばブラックジャックの場合、番号の合計を求め21を超えない数で21に近い方が勝ちます。
しかし、C++の変数はprivateに入っているケースが多く、合計を求めようとすると専用の関数が必要になります。
トランプのカードクラスを単純化したクラスの例を書きます。
<sample program cpp061-01>
#include <iostream> class Card { public: Card(const int suit, const int number); private: int m_suit; int m_number; }; int main() { Card card1(0, 5); Card card2(1, 2); return 0; } Card::Card(const int suit, const int number) : m_suit(suit), m_number(number) { } |
引数を持ったコンストラクタ関数を作り、初期値を与えた状態です。
この2枚のカードの番号を加算して合計値を求めたい場合、次のような関数になるでしょう。
<sample program cpp061-02>
#include <iostream> class Card { public: Card(const int suit, const int number); int Add(const Card &rhs); private: int m_suit; int m_number; }; int main() { Card card1(0, 5); Card card2(1, 2); int sum = card1.Add(card2); std::cout << "sum = " << sum << std::endl; return 0; } Card::Card(const int suit, const int number) : m_suit(suit), m_number(number) { } int Card::Add(const Card &rhs) { return m_number + rhs.m_number; } |
<実行結果>
sum = 7 続行するには何かキーを押してください・・・
加算するための関数、Addを作りました。
本体を見ると、
int Card::Add(const Card &rhs) { return m_number + rhs.m_number; } |
となっています。
呼び出し部分を見ると、
card1.Add(card2); |
となっていますね。
クラスのメンバ関数ですから、カードクラスの実体であるcard1が関数を呼び出しています。
そして、引数としてcard2が渡されています。
card1の受け取りは「const参照」でrhs(右辺)という名前になっています。
大事な事は、同じCardクラスですから、お互いのprivateにアクセス出来ると言う事です。
card1のm_numberとrhs(card2)のm_numberを加算した結果をreturnしています。
これで、2つのクラスのメンバ変数m_numberの加算が出来ました。
Javaなどの言語では、このように加算関数を作ってメンバ変数同士を計算します。
しかし、C++にはもっと強力な機能が機能が用意されているのです。
その機能を「演算子オーバーロード」と言います。
関数のオーバーロードと同じく、演算子もオーバーロード出来るのです。
オーバーロードとは「多重定義」と言う意味でした。
同じ名前の関数に、異なる処理を割り当てる事が出来る機能です。
演算子も同じように、別の機能を持たせる事が出来るのです。
例えば、+演算子に色々な意味を持たせる事が出来ます。
※ただし、+演算子に減算や乗算など全くイメージの異なる機能を持たせる事はご法度です!
それでは、上のプログラムを演算子オーバーロードを使ったプログラムに変えてみます。
<sample program cpp061-03>
#include <iostream> class Card { public: Card(const int suit, const int number); int operator+(const Card &rhs) const; private: int m_suit; int m_number; }; int main() { Card card1(0, 5); Card card2(1, 2); int sum = card1 + card2; std::cout << "sum = " << sum << std::endl; return 0; } Card::Card(const int suit, const int number) : m_suit(suit), m_number(number) { } int Card::operator+(const Card &rhs) const { return m_number + rhs.m_number; } |
<実行結果>
sum = 7 続行するには何かキーを押してください・・・
結果はAdd関数を使った時と同じです。
まずはプロトタイプ宣言を見ましょう。
int operator+(const Card &rhs) const; |
最初は分かりにくいかも知れませんが、関数と同じように考えて大丈夫です。
int型を返す、「opeartor+」という関数で、引数としてCardクラスの「const参照」を受け取ります。
メンバ変数は書き換えませんので、後ろに「const」も付いています。
この「関数」はクラスの実体の後ろに「+」と書いた時点で呼び出され、右辺が引数として渡されます。
本体を見ると、
int Card::operator+(const Card &rhs) const { return m_number + rhs.m_number; } |
前のAdd関数と変わりません。
しかし、呼び出している箇所を見ると、
int sum = card1 + card2; |
関数呼び出しには見えず、単純に加算しているように見えます。
こちらの方が直観的で非常に分かりやすいです!
この「演算子オーバーロード」は様々な場面で役に立つ機能ですので、ぜひ習得して欲しい機能の1つです。
※Javaでは使えませんが、C#では使えます!