#pragma twice

KAB-studio > プログラミング > #pragma twice > 221 Version 11.21 「演算子のオーバーロード」の意味

#pragma twice 221 Version 11.21 「演算子のオーバーロード」の意味

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

 Version 11.21
演算子のオーバーロードの意味

今回も前回の続き、演算子のオーバーロードについて見ていきます
え? 前回でだいたいやっちゃったと思うんだけど
ところがそうじゃないんです。演算子のオーバーロードは、奥が深いって
いうか、複雑というか、ややこしいというか……
よーするにアレなのね、アレ
まぁそんなところ。というわけで、さらにややこしい部分について見てい
きます。まず、新しく CTestString ってクラスを作ることを考えます。こ
のクラスは

    CTestString cTestString = "あいうえお";
    TRACE( "%s\n", cTestString.GetData() );
    // あいうえお

という感じに、コンストラクタで文字列を渡すと中に持って、 
GetData() で取得できる、っていうクラスとします
うん
これに + 演算子のオーバーロードを持たせるとします

    CString cStr;
    cStr = cTestString + "かきくけこ";
    TRACE( "%s\n", cStr );
    // あいうえおかきくけこ

こーゆーのって CString ではできるよね
そう。まぁここから説明するのは全部 CString でもしてることだからそ
れを参考にしてもいいんだけど、それだと作る練習にはならないから
はーい
で、実際にこの機能を CTestString に入れると、 CTestString はこうな
ります

class CTestString
{
private:
    CString m_cStr;
public:
    // コンストラクタ。
    CTestString( CString p_cStr )
    {
        m_cStr = p_cStr;
    }

    // + 演算子。
    CString operator + ( CString p_cStr )
    {
        return m_cStr + p_cStr;
    }

    // データ出力。
    CString GetData() const
    {
        return m_cStr;
    }
};

うん、この辺は前とほとんど同じだからわかる……けど?
そう、ここまでは復習段階。で、今回説明するのは

    cStr = "かきくけこ" + cTestString;

ってできるようにする方法
できないの?
うん、ビルドしてみて
エラーになった

error C2679: 
二項演算子 '+' : 型 'class B1::CTestString' の右オペランドを扱う
演算子は定義されていません。(または変換できません)

どういうこと?
つまり〈 文字列 + CTestString 〉はできませんよってこと。実は、二項
演算子のオーバーロード関数は、演算子の右側に値が来ないと呼ばれないん
です
んーつまり

    CString operator + ( CString p_cStr )

だったら

    cStr = cTestString + "かきくけこ";

じゃなきゃいけないってこと?
そういうこと
 i++ で呼ばれるのは?
それは単項演算子だから別。というかそれはかなり特別だし
型変換のも別?
そう、あれも別
つまり、 + とか = とか、そういう二項演算子系は、左側に自分のクラス
を、右側に渡す値が来ないと呼べないんだ
そういうこと
でも、 CString はできる、だから方法はあるんだよね
もちろん。それをこれから説明します。二項演算子の制限は、クラスのメ
ンバ関数だったから。で、実は演算子のオーバーロードは普通の関数として
も作ることができるんです
普通の関数って、メンバ関数じゃない、クラスの中にない関数ってこ
と?
そういうこと。たとえばこんな感じに

/**
    + 演算子のオーバーロード。
    グローバル関数版。
*/
CString operator + 
    ( CString p_cLStr
    , CTestString p_cRTestString 
    )
{
    return p_cLStr + p_cRTestString.GetData();
}

なんか変……
関数名とかなくていきなり operator だからね。でも、基本的にはメンバ
関数のものと同じ。違うのは、引数が多いこと
二項演算子だから、引数がふたつってこと?
そういうこと。使用例はこんな感じ

// 使用例。
void Use_GlobalPlus()
{
    CTestString cTestString = "あいうえお";
    TRACE( "%s\n", cTestString.GetData() );
    // あいうえお

    CString cStr;
    cStr = "かきくけこ" + cTestString;
    TRACE( "%s\n", cStr );
    // あいうえおかきくけこ
}

この中の

    cStr = "かきくけこ" + cTestString;

は、さっきの関数の

CString operator + 
    ( CString p_cLStr               // < "かきくけこ"
    , CTestString p_cRTestString    // < cTestString
    )

に入るんです
で、中で p_cRTestString.GetData() 呼んで文字列取り出して、 
CString どうしだから足して、それを返してる……と
そういうこと。これとメンバ関数版の両方を用意すれば
 + は完璧ってことね。……? もしかして、演算子のオーバーロードを
するときって、かなり大変?
大変だね。ひととおりの演算子に対応させるには、それだけの数、関数を
用意しなきゃいけないからね
めんどくさー
でも、たとえば上の例、 - 演算子は必要だと思う?
文字列から文字列を引く……なんかイメージわかないね
そういう場合には無理に作る必要ないから
必要なものだけ作ればそんなに大変じゃないわけね
さて、ここで注意。たとえばこういうのは作れません

/**
    + 演算子のオーバーロード。
*/
int operator + 
    ( int p_iL
    , int p_iR
    )
{
    TRACE( "%d + %d = %d", p_iL, p_iR, p_iL + p_iR );
    return p_iL + p_iR;
}

引数ふたつとも int ……って、それって普通の + と同じじゃない
そう。たとえばこういう例みたいに、普通の + 演算子をオーバーロード
して、その中にデバッグ機能を入れたいなーとかって場合もあるわけです
確かにこれはちょっと便利そう
でもこれはできないんです

error C2803: 
'operator +' の宣言で、クラス型のパラメータが 1 つも
指定されていません。

ってコンパイルエラーが出た
演算子のオーバーロードをするときには、かならず引数のどれかがクラス
じゃないといけないんです
クラスじゃない、つまり両方とも int はだめ、と。ってことは、元々あ
るのは変えられないってことね
そういうこと。で、ここからはちょっと脱線というか、難しい話なんだけ



/**
    + 演算子。
*/
int operator + 
    ( int p_iL
    , int p_iR
    )
{
    return p_iL + p_iR;
}

なにこれ。てか普通の + だね
プログラマー的な考え方をした場合、こういう関数がどっかに隠れてる、
って考えて欲しいかなと
……どゆこと?
たとえば

    int i = 100 + 200;

って書いてあったら、どっかにあるこの関数が呼ばれてるんだって
そう考えるってこと?
そう。そうすると、なんで〈演算子の【オーバーロード】〉なのかって
あ……そか、もしこういう関数があるなら、その引数違いの関数を作るっ
てことになるから
そう、納得できるでしょ?
でもこじつけっぽい
う”

/*
    Preview Next Story!
*/
オーバーロードって複雑ねー、使うだけなら便利なんだけど
それって危険かも
そなの?
使えるだけで仕組みを知ってないと、危険なことって結構あるよ
 CString なんてすごく簡単に使えそうだけど
というわけで次回
< Version 11.22 CString の注意点 >
につづく!
蛇口をひねると水が出る、ってだけじゃダメってこと
ダメなの?
たぶん……
 
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
RSSに登録
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
 
このページは、Visual C++ 6.0を用いた C++ 言語プログラミングの解説を行う#pragma twiceの一コンテンツです。
詳しい説明は#pragma twiceのトップページをご覧ください。