#pragma twice

KAB-studio > プログラミング > #pragma twice > 343 Version 16.16 演算子のオーバーロードとオペランド

#pragma twice 343 Version 16.16 演算子のオーバーロードとオペランド

前のページへ 表紙・目次へ 次のページへ

 Version 16.16
演算子のオーバーロードとオペランド

前回は演算子のオーバーロードについて復習しました
っていうか、カンマのオーバーロードって変すぎるんだけど!
これだね

// , 演算子のオーバーロードメンバ関数。
CData & CData::operator , ( int p_i )
{
    // 引数をメンバ変数にセットします。
    m_iData = p_i;

    // 自分の参照を返します。
    return *this;
}

っていうかこれ作れって言われても絶対作れないんだけど
そうでもないよ。演算子のオーバーロードには、ちゃんとしたルールがあ
るんです
え、ルールが? それ憶えてればどんなのも作れるってこと?
そういうこと。まず、演算子には単項演算子と二項演算子がある、ってい
うのを思い出して
単項演算子は Version 6.09 ( No.109 ) で、二項演算子は 
Version 6.10 ( No.110 ) でやったね
まずは二項演算子に限定して説明します。二項演算子は、演算子を挟んで
ふたつの値を指定します。この値のことを【オペランド】と言いました
うん、たとえば

    m_iData = p_i;

だったら

・左オペランド:m_iData
・右オペランド:p_i

なんだよね
そうそう。これは、全ての二項演算子で同様です。【,】であってもね
そういえばそうだ……
さて、二項演算子をオーバーロードする場合、メンバ関数は以下のように
なります

戻り値の型 左オペランドの型::operator 演算子 ( 右オペランドの型 )

左オペランドと右オペランド……
たとえば、以下のように ,演算子をオーバーロードしたい場合

    cData , 100;

左オペランドは CData クラス、右オペランドは int 型になるから、以下
のようになります

戻り値の型 CData::operator , ( int p_i )

あ、こういうふうに決まるんだ!
まずは使い方を決めて、そこから、左オペランドを自クラス、
右オペランドを引数ってすればいいわけ
あれ? でもこれって CData クラスのメンバ関数だよね。左オペランド
が CData クラスじゃない場合にはどうするの?
そのクラスのメンバ関数にすればいいってこと。つまり、左オペランドの
クラスのメンバ関数にして、右オペランドは引数に、ってすればいいってこ

? それはそうなんだけど……たとえばさ、左右逆に

    100 , cData;

ってしたい場合にはどうするの?
その場合には、ちょっとルールが変わります。左オペランドのクラスの
メンバ関数にする、っていうルールは変わらないから、こういうふうに 
int 等の基本型が左オペランドになる場合には、メンバ関数としては作成で
きません
メンバ関数としてはできない……ってことは、普通の関数としてはでき
る、ってこと?
そういうこと。メンバ関数ではない、普通の関数の場合、以下のルールに
なります

戻り値の型 operator 演算子 ( 左オペランドの型, 右オペランドの型 )

あ、メンバ関数じゃなくなったら、引数が2つに増えた
普通の関数の場合、左オペランドが第1引数、右オペランドが第2引数にな
ります
なんか、前に言ってた、 this が隠し引数になっている、って話に似て
るかも
 Version 16.03 ( No.330 ) で説明したことだね。確かにちょっと似てる
かも。この普通の関数の方が基本で、メンバ関数版は、第1引数を this に
した、って考えると分かりやすいかもね
うん、そうかも
最初の例も含めて、メンバ関数ではなく普通の関数にした場合には、以下
のようになります

// Data.h

// CDataクラス。
class CData
{
public:
    // private メンバ変数。
    int m_iData;
};

// , 演算子のオーバーロードメンバ関数。
CData & operator , ( CData &p_rcData, int p_i );
CData & operator , ( int p_i, CData &p_rcData );


// Data.cpp
#include <Windows.h>
#include <stdio.h>

#include "Data.h"

// , 演算子のオーバーロードメンバ関数。
CData & operator , ( CData &p_rcData, int p_i )
{
    p_rcData.m_iData = p_i;

    return p_rcData;
}

CData & operator , ( int p_i, CData &p_rcData )
{
    p_rcData.m_iData = p_i;

    return p_rcData;
}


// Main.cpp
#include <Windows.h>
#include <stdio.h>

#include "Data.h"
int WINAPI WinMain
    ( HINSTANCE p_hInstance
    , HINSTANCE p_hPrevInstance
    , LPSTR p_pchCmdLine
    , int p_iCmdShow
    )
{
    // CData クラスの変数を宣言します。
    CData cData;
    // ,演算子のオーバーロードメンバ関数を使用します。
    cData , 100;
    100 , cData;

    return 0;
}

あれ! メンバ関数じゃなくてもいいんだ!
別にメンバ関数でもメンバ関数じゃなくてもいいんです。便利な方を選択
すればいいわけ。クラスによってはメンバ関数化できないこともあるしね
んー、メンバ関数化できないのは分かるけど、今回みたいな場合にはどっ
ちがいいの?
演算子によるかな。たとえば、 = 演算子の場合にはメンバ関数の方がいい
と思うよ。自クラスが右オペランドにくることはないし、何よりメンバ関数
なら private メンバ変数にアクセスできるから
そっか、 = 演算子だと代入だから、 private メンバ変数にアクセスでき
る方が便利なんだ
 + 演算子の場合には、普通の関数がいいかな。 + 演算子はオペランドに
変更を加えないし、ほとんどの場合左右のオペランドを入れ替えたものが必
要になるから、片方だけメンバ関数っていうよりは両方とも普通の関数の方
がいいだろうし
それが今回の , 演算子の例ね
そういうこと。こういう使い分けが必要かな
使い分け……質問!
はい火美ちゃん
両方あっちゃだめ? メンバ関数版と普通の関数版、こんな感じに

// , 演算子のオーバーロードメンバ関数。
CData & CData::operator , ( int p_i )
{
    // 引数をメンバ変数にセットします。
    m_iData = p_i;

    // 自分の参照を返します。
    return *this;
}

CData & operator , ( CData &p_rcData, int p_i )
{
    p_rcData.m_iData = p_i;

    return p_rcData;
}

そうすると、どっちを使えばいいのか分からないからコンパイルエラーに
なるんです

    cData , 100;
    // コンパイルエラー:
    // error C2593: 'operator ,' があいまいです。

なるほど、確かにあいまいだよね
演算子のオーバーロードは、ルールが厳しいようで、実はいろんな表記方
法があるんです。その分、こういう曖昧さを生む可能性があるから、慣れて
くるとその解決の方が難しいかも

/*
    Preview Next Story!
*/
うん、なんか演算子のオーバーロードが使いやすくなったかも
こういうルールが分かれば難しくないかもね
……でも難しいとこ多いけど。参照を使う所とか
演算子のオーバーロードと参照は切っても切れない関係なんです
切っても切れない?
というわけで次回
< Version 16.17 演算子のオーバーロードの戻り値の型 >
につづく!
オーバーロードのために参照が作られたとか?
そこまでは言わないけど……いや、もしかしたら……
 
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
RSSに登録
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
 
このページは、Visual C++ 6.0を用いた C++ 言語プログラミングの解説を行う#pragma twiceの一コンテンツです。
詳しい説明は#pragma twiceのトップページをご覧ください。