#pragma twice

KAB-studio > プログラミング > #pragma twice > 129 Version 7.09 演算子のオーバーロード

#pragma twice 129 Version 7.09 演算子のオーバーロード

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

 Version 7.09
演算子のオーバーロード

えーっと、今日は難しいからちょっと気を抜いててもいいよ
なにぃ!? なんか矛盾してるってそれ
コンストラクタもそうだけど、〈使う側〉の場合はそんなに厳密に理解し
てなくても使えるわけだから
っつーことは、使う段階になったら真面目に憶えなきゃいけないわけね
そゆこと。で、今回は前回の続き

void CAnimeDlg::OnBDraw() 
{
    CRect cRect;
    ::GetWindowRect( GetSafeHwnd(), cRect );
    TRACE
        ( "%d, %d, %d, %d\n"
        , cRect.left, cRect.top
        , cRect.right, cRect.bottom );
}

そうそう、ホントは &cRect じゃなきゃいけないはずなのに、 & が付い
てないのよねー
あ、ちなみに

void CAnimeDlg::OnBDraw() 
{
    RECT stRect;
    ::GetWindowRect( GetSafeHwnd(), stRect );
    // error C2664: 'GetWindowRect' : 
    // 2 番目の引数を 'struct tagRECT' から 'struct tagRECT *' に
    // 変換できません。
}

あ、ビルドでエラーになった
つまり RECT 構造体にはこの機能はありません。 CRect の機能だから
コンストラクタみたく、 CRect にそういう機能が付けられてるわけね
で、この仕組みを見る前に、もうひとつ、別の機能も見て

void CAnimeDlg::OnBDraw() 
{
    CRect cRect1;
    ::GetWindowRect( GetSafeHwnd(), &cRect1 );
    CRect cRect2;
    ::GetWindowRect( GetSafeHwnd(), &cRect2 );
    if( cRect1 == cRect2 )
    {
        TRACE( "cRect1 == cRect2\n" );
    }
    // cRect1 == cRect2
}

ん? 同じだよね、 cRect1 と cRect2 って
だから一致します
なるほど。で?
このコードのポイントは、 cRect1 == cRect2 。実は、クラスや構造体は
== で普通に比較できないんです
え、そうなの?
やってみようか。 RECT の場合

void CAnimeDlg::OnBDraw() 
{
    RECT stRect1;
    ::GetWindowRect( GetSafeHwnd(), &stRect1 );
    RECT stRect2;
    ::GetWindowRect( GetSafeHwnd(), &stRect2 );
    if( stRect1 == stRect2 )
    {
        TRACE( "stRect1 == stRect2\n" );
    }
    // error C2678: 二項演算子 '==' : 型 'struct tagRECT' の左
    // オペランドを扱う演算子は定義されていません。
    // (または変換できません)
}

ホントだ、エラーになった
構造体やクラスで比較をする場合には、メンバ変数ひとつずつ比較しなき
ゃダメ。 == だけじゃなく、 + とかの四則演算系とかもそう
面倒ねー。あ、だから CRect にはそういう機能がある!
そのとおり! まずは MSDN の方を見てみようか
ほい、 CRect のメンバ関数一覧っと
下の方に〈演算子〉ってあるでしょ
ある。 operator LPCRECT とか operator == とか。これが?
そうこれが。まず、ここに書いてある【 operator 】は無視して読んで
無視すると、演算子がずらーり
その演算子は、このクラスに使えるって事
だから == を使えるってことね
演算子じゃないの、たとえば LPCRECT とかは、この型には自動的にキャ
ストできるってこと
あ! これがあるから & 付けなくていいんだ。 LPCRECT って、 RECT の
ポインタだよね
そう、 const 版。 非 const なのは LPRECT の方
それもちゃんとあるね const が渡すの専用で、 const 付いてないのが受
け取り用、だって
 Ver 4.15 ( No.065 ) でやったね。 GetWindowRect() は
 LPRECT が引数になってるから LPRECT の方が呼ばれるんだね
ブレークポイント置いてステップインすれば確認できるから
え……ってことは、これってメンバ関数なの?
そう。 operator == のページを見てみて
ほい。ホントだ、引数が const RECT& で、戻り値が BOOL だ
ちなみに引数が RECT の参照だから
ってことは……

void CAnimeDlg::OnBDraw() 
{
    CRect cRect1;
    ::GetWindowRect( GetSafeHwnd(), &cRect1 );
    RECT stRect2;
    ::GetWindowRect( GetSafeHwnd(), &stRect2 );
    if( cRect1 == stRect2 )
    {
        TRACE( "cRect1 == stRect2\n" );
    }
}

うお通った!
ちなみに参照については Ver 4.14 ( No.064 ) の見てください
あれ? じゃぁ……

void CAnimeDlg::OnBDraw() 
{
    RECT stRect1;
    ::GetWindowRect( GetSafeHwnd(), &stRect1 );
    CRect cRect2;
    ::GetWindowRect( GetSafeHwnd(), &cRect2 );
    if( stRect1 == cRect2 )
    {
        TRACE( "stRect1 == cRect2\n" );
    }
    // error C2678:(以下略)
}

げ、エラー!
そう、二項演算子って憶えてる?
 Ver 6.10 ( No.110 ) でやったね。演算子の左と右に変数取るのだね
そうそう。 cRect1 == cRect2 ってのも二項演算子だけど、この二項演算
子をメンバ関数として持つ場合、左オペランドのメンバ関数として呼ばれる
から
ってことは、 cRect1 のメンバ関数として呼ばれて……右オペランドの
cRect2 が引数として渡される!
そう! 上のでエラーが出ちゃうのは
 RECT には == のメンバ関数ないから
ってこと。このルールさえ憶えておけば、あとはメンバ関数と同じかな。
あ、ちなみに

    if( cRect1.operator ==( stRect2 ) )

な、なにこれ?
 cRect1 == cRect2 を、メンバ関数っぽく呼んだ例
ちゃんとコンパイル通る……
というわけで、メンバ関数になってる部分を見てみましょう

( Afxwin1.inl より抜粋)
_AFXWIN_INLINE BOOL CRect::operator==(const RECT& rect) const
    { return ::EqualRect(this, &rect); }
(抜粋ここまで)

な、なんかよくわかんない……
うん、だから〈メンバ関数っぽい〉ってとこだけ解ってもらえればいいか

あ、気を抜いていいんだもんね
そゆこと。とりあえずポイントは operator 。 == とかの演算子をクラス
のメンバ関数にする場合には、必ずこれを前に付けます
……それだけ聞くと簡単そうに聞こえる……
ま、上のコードは余分な情報が多いから解りにくいんだと思うよ。今回関
わってくる部分は operator だけだから
この部分はそれほど難しくないってことね
で、こういう〈演算子をクラスに使えるようにする機能〉のことを、
【演算子のオーバーロード】って言います
うわ、なんか難しそうな用語が!
ま、これは今はこのまんま憶えてもらっちゃってもいいや。
【オーバーロード】ってものについては今度別にちゃんと教えるから
げ、なんかまだ他に難しい事が?
だから難しいんだってば
難しかったり簡単だったり……
ちなみにこの演算子のオーバーロードは CString にもあったりします
うん、前にやったね。 operator LPCTSTR とか
 Ver 5.22 ( No.087 ) だね。でも、実際にはこの演算子のオーバーロー
ドがされてるクラスって多くないんだよね
そういえば、他の MFC クラスを見てもないね。便利じゃないのねー
でも、そうとも言えないんだよね
どゆこと?
たとえば operator LPCRECT 。これを使うと CRect をそのまま渡せ
ちゃうでしょ。ポインタとしてじゃなくて
うん、 & 付けないでね
こういうのってちょっと危なっかしいんだよね。もしポインタとかアドレ
スとかちゃんと知らないでこういうのを使っちゃうと
クラスだとそのまま渡せちゃう、とか思っちゃいそうだね
あと CString だと operator + () とかあるから、これで文字列をくっつ
けられるんだけど
これも普通の文字配列ならできないもんね、ポインタどーしだから
演算子のオーバーロードは、使ってるとこが〈目に見えない〉、つまりい
つの間にか使っちゃってることが多いんだよね
だからむやみにいろんなクラスに着いてたりはしないんだ
本来は初心者向けの機能なんだろうけど、むしろこれは、ちゃんと理解し
てる上級者向けの機能なのかもね

/*
    Preview Next Story!
*/
難しかったり難しくなかったり
うん、それは言えるかも。たとえば _AFXWIN_INLINE とか
知らないもの……だけど、全部大文字だから、マクロ?
そ。これは調べれば解ること。でも CRect::operator==() const の
 const って何……なんでこんなとこに付いてるの……
これなんかは調べるのも難しいもののひとつかも
というわけで次回
< Version 7.10 いろんな描画モード >
につづく!
で、この const はなんなの?
これはメンバ変数の書き換えを防ぐもので……続ける?
その調べるのも難しいことをすらっと言う水希ちゃんて……
 
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
RSSに登録
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
 
このページは、Visual C++ 6.0を用いた C++ 言語プログラミングの解説を行う#pragma twiceの一コンテンツです。
詳しい説明は#pragma twiceのトップページをご覧ください。