#pragma twice

KAB-studio > プログラミング > #pragma twice > 345 Version 16.18 単項演算子のオーバーロード

#pragma twice 345 Version 16.18 単項演算子のオーバーロード

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

 Version 16.18
単項演算子のオーバーロード

前回は、演算子のオーバーロードの戻り値について説明しました
参照にしている理由ってやつね
今回は、単項演算子のオーバーロードをしてみます
単項演算子ってことは、オペランドがひとつのだよね、 ++ 演算子とか 
! 演算子とか
そう。とりあえず ! 演算子を使ってみようか。メンバ関数として作ると
こんな感じになります

// Data.h

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

public:
    // ! 演算子のオーバーロードメンバ関数。
    BOOL operator ! ();
};


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

#include "Data.h"

// ! 演算子のオーバーロードメンバ関数。
BOOL CData::operator ! ()
{
    // 有無を言わさずTRUEを返します。
    return TRUE;
}

あ、引数がない
使用例はこうなります

// 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;
    // ! 演算子を使用します。
    if( !cData )
    {
        OutputDebugString( "cData.m_iData == FALSE\n" );
    }
    // cData.m_iData == FALSE

    return 0;
}

この〈 if( !cData ) 〉が、使用しているところです
こうすると、 ! 演算子のオーバーロード、つまり CData クラスの
operator ! () メンバ関数が呼び出されて、絶対に TRUE 返すから
 if の中が処理される、という仕組みというわけです
引数ないんだね
そう。二項演算子の引数のルールってどうだった?
えっと……

・メンバ関数:左オペランドが this 、右オペランドが引数
・普通の関数:左オペランドが第1引数、右オペランドが第2引数

って感じだった
単項演算子の場合には、単純に右オペランドがない、って考えればいいか
ら。メンバ関数版の場合
 this がオペランドになるんだね。ってことは、普通の関数版は、
オペランドひとつってこと?
そういうこと。普通の関数にすると、以下のようになります

// Data.h

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

// ! 演算子のオーバーロード関数。
BOOL operator ! ( CData &p_rcData );


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

#include "Data.h"

// ! 演算子のオーバーロード関数。
BOOL operator ! ( CData &p_rcData )
{
    // 有無を言わさずTRUEを返します。
    return TRUE;
}

普通に、 CData の参照が引数に追加されただけ……二項演算子の時と同
じだね
そう考えると分かりやすいかな。二項演算子のルールが分かっていれば、
単項演算子のルールも分かると思うよ
うん、単項演算子の方がオペランド少ないんだし
さて。単項演算子にはちょっとやっかいなものがあります。それは 
++ 演算子と -- 演算子
やっかいなの?
 Version 11.20 ( No.220 ) で説明したように、この演算子には前置と
後置の二種類あるんです
あ! そういえばそうだった!
前置と後置の話は Version 2.7 ( No.018 ) でしたね。前置は普通に増減
するけど、後置の場合は次の行に移らないと増減しません
だから後置は使うなって話よね
分かりにくいからね。実際、後置の ++ 演算子と -- 演算子は、
オーバーロードが面倒になっています
単項演算子で、メンバ関数にしても引数が必要なんだね
だから後置の方は作らない方がいいと思います。ただ、前置の方はよく使
うから作れるようにしておいて
ほーい
あと、憶えておいて欲しいことがあります

・オペランドのいずれかが、必ずクラスである必要がある

どういうこと?
つまり、こういうのは作れないって事

// Data.cpp

// int 型に対する + 演算子のオーバーロード。
int operator +( int p_iL, int p_iR )
{
    return 0;
}

これってつまり、 100 + 200 ってことだよね
そう、両オペランドが int 型。オペランドにクラスがないと、コンパイル
エラーになります

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

あらら。ってことはー……つまり、普通の演算子の機能を消して、新しい
機能に書き換える、ってことはできないってこと?
そういうこと。演算子のオーバーロードは、あくまでクラスに対して新し
い演算子の使い方を追加する、っていう意味だから
元々あるのは変えられない、と。あれ? これは普通の関数だけど、
メンバ関数版の場合は?
……メンバ関数版は、左オペランドが?
自クラス。あ、メンバ関数版はそれだけでもうクラス使ってるんだ
そういうこと。逆に言うと、メンバ関数版なら大丈夫、ってことだね
必ずクラスがオペランドになるわけだもんね
さて、このように〈オペランドにクラスが必要〉という制限はあるわけだ
けど、逆に言えばそれだけ、ということ
どういうこと?
たとえば、 API の構造体や、 MFC のクラスといった、既存のクラスに対
して演算子のオーバーロードを行うことができるんです
構造体に?
たとえば、 Version 7.06 ( No.126 ) で使用した RECT 構造体に、 
+ 演算子を使用してみます

    RECT stRect1;
    stRect1.left = 100;
    stRect1.top = 200;
    stRect1.right = 300;
    stRect1.bottom = 400;

    RECT stRect2;
    stRect2.left = 1;
    stRect2.top = 2;
    stRect2.right = 3;
    stRect2.bottom = 4;

    // += 演算子を使用してみます。
    stRect1 += stRect2;
    // コンパイルエラー:
    // error C2676: 二項演算子 '+=' : 
    // 'struct tagRECT' は、この演算子または定義済の演算子に適切な
    // 型への変換の定義を行いません。

うん、できないよね……
でも、 += 演算子をオーバーロードしてしまえば……

// RECT 構造体の += 演算子のオーバーロード。
RECT & operator +=( RECT &p_rstRectL, RECT &p_rstRectR )
{
    p_rstRectL.left   += p_rstRectR.left;
    p_rstRectL.top    += p_rstRectR.top;
    p_rstRectL.right  += p_rstRectR.right;
    p_rstRectL.bottom += p_rstRectR.bottom;
    return p_rstRectL;
}

これができちゃう!
つまり、演算子のオーバーロードは既存の構造体やクラスにも使えるって
こと。ただ、これをしちゃうと動くものが動かなくなりそうだから、危険な
テクニックかも……

/*
    Preview Next Story!
*/
演算子のオーバーロードは奥が深い……
深すぎるけどね
あれ、そんなこと言うなんて意外
便利すぎるものほど危険なんだけどね
ほほう
というわけで次回
< Version 16.19 型変換演算子のオーバーロード >
につづく!
だからC++はやめられないんだよね
ダメじゃん
 
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
RSSに登録
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
 
このページは、Visual C++ 6.0を用いた C++ 言語プログラミングの解説を行う#pragma twiceの一コンテンツです。
詳しい説明は#pragma twiceのトップページをご覧ください。