#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のトップページをご覧ください。