#pragma twice

KAB-studio > プログラミング > #pragma twice > 220 Version 11.20 演算子をオーバーロードしよう

#pragma twice 220 Version 11.20 演算子をオーバーロードしよう

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

 Version 11.20
演算子をオーバーロードしよう

今回は演算子をオーバーロードしてみます
演算子のオーバーロードって、クラスで演算子使うためのだよね
そう、 Version 7.09 ( No.129 ) でやったね。今回はこれを作ってみま
す。まずは基本的な例から

// 演算子のオーバーロード。
class CHasOperator
{
private:
    int m_i;
public:
    // 演算子のオーバーロード。
    int operator = ( int p_i )
    {
        m_i = p_i;
        TRACE( "= %d\n", m_i );
        return m_i;
    }
};

やっぱなんか見慣れない……
使い方はこう

// 使用例。
void Use_CHasOperator()
{
    CHasOperator cHasOperator;
    cHasOperator = 100;
    // = 100
}

 = でメンバ関数呼べるようになる、ってことだよね
そう。オーバーロードの構文はこんな感じ。

    戻り値 operator 演算子 ( 引数 )
    {
        // メンバ関数の本体。
    }

結構自由度は高いから。戻り値や引数は好きなものにできるよ
今回は戻り値が int 、引数も int ね。戻り値って必要?
場合によるかな。たとえば、普通の int の場合

    int i1;
    int i2;
    i1 = i2 = 100;

っていうふうに〈他に代入したのをまた他に代入〉っていうことができる
んです。戻り値を int にしておけば、同じように

    CHasOperator cHasOperator1;
    CHasOperator cHasOperator2;
    cHasOperator2 = cHasOperator1 = 100;
    // = 100
    // = 100

っていうことができるんです
こうすればより演算子に似るわけね
言い換えると、演算子に似た使い方ができるようにするには、色々とコツ
が必要なんです
確かに、これは知らないとできないね
それと、演算子にできるだけ似せることがコツのひとつとも言えるかな
どゆこと?
たとえば

    // 演算子のオーバーロード。
    int operator = ( int p_i )
    {
        m_i -= p_i; // <ここ。
        TRACE( "= %d\n", m_i );
        return m_i;
    }

あ、 -= になってる
演算子のオーバーロードをすると、こういうこともできちゃうんだけど、
こういうことをすると混乱の元だからやめた方がいいかな
 = だったら中に代入するだけ、って感じに演算子に似せるわけね
そゆこと。あと、引数の数に関しては制約があって、こっちはちょっと難
しいかも。 Version 6.09 ( No.109 ) で【単項演算子】や【二項演算子】
ってやったでしょ
演算子にくっつける変数の数だね。あ! そっか、それが引数の数になる
んだ
そういうこと。オペランドのひとつは自分自身になるから、 1 引いた数
が引数の数ってことだね。たとえば、 ++ は単項演算子だからオペランドは
ひとつ
で、自クラスの 1 をひくと……ゼロだね
だから、引数はいらなくなります

// 演算子のオーバーロード。
class CHasOperator_Increment
{
private:
    int m_i;

public:
    // コンストラクタ。
    CHasOperator_Increment()
    {
        m_i = 0;
    }

    // ++ 演算子のオーバーロード。
    int operator ++()
    {
        ++m_i;
        TRACE( "++ %d\n", m_i );
        return m_i;
    }
};

使用例はこんな感じ

void Use_CHasOperator_Increment()
{
    CHasOperator_Increment cHasOperator;
    ++cHasOperator;
    // ++ 1
}

ってことは、演算子ごとにそういうの考えなきゃいけないの?? めんど
くさー
さらにめんどくさいことに、 ++ って ++i っていう形式と i++ っていう
形式とふたつあったでしょ
 ++i が先に 1 増やして、 i++ があとで 1 増やすんだよね
そう、 Version 2.7 ( N0.018 ) でやったね。このふたつは区別されて
て、 i++ の方を作りたい場合には int の引数ひとつを入れることになって
ます

    // 後置 ++ 演算子のオーバーロード。
    int operator ++ ( int p_i )
    {
        ++m_i;
        TRACE( "++ %d\n", m_i );
        return m_i;
    }

なんかややこしいね……
あらかじめ言っておくと、これからさらにややこしくなるから
げ!
なぜかっていうと、元々あった仕様に無理矢理追加したから
演算子のオーバーロードってあとから付け加えたものってこと?
そういうこと。だから色々と矛盾とか問題とかあるんです
……使わない方がよくない?
微妙だね。メリットも多いから使った方がいいけど、他の言語では採用さ
れてないから、むしろデメリットの方が多いって考え方もあるかも
うーん……
でも、 C++ やる上では必要だから
う”、つまり私は勉強しなきゃいけないってこと?
そゆこと
うー
最後に、型変換をしてくれるオーバーロードを紹介します
型変換?
 Version 5.22 ( No.087 ) や Version 7.09 ( No.129 ) で紹介した、自
動的に他の型にくれる機能のこと
あー、 CString を LPCTSTR に、とかね
そうそれ。というわけでその例がこれ

// 演算子のオーバーロード。
class CHasOperator_Return
{
private:
    int m_i;

public:
    CHasOperator_Return()
    {
        m_i = 0;
    }

    // 型変換演算子のオーバーロード。
    operator int()
    {
        TRACE( "(int)%d\n", m_i );
        return m_i;
    }
};

使用例はこんな感じ

void Use_CHasOperator_Return()
{
    CHasOperator_Return cHasOperator;
    int i = cHasOperator;
    TRACE( "%d\n", i );
    // (int)0
    // 0
}

おー、 int に渡せば operator int() が呼ばれるってわけね。でもこの
関数、戻り値なくて変……
戻り値は決まってるから必要ないって事みたいだね
決まってる? あ、そっか、 int に渡すんだから int なんだ。……あ
れ? でもさ、オーバーロードって、戻り値で選べないんじゃないの?
うん、だからこれは特別。書き方も使い方も特別って感じかな
なんか変なの。便利だけど

/*
    Preview Next Story!
*/
なんか、今までと勝手が違うかも
便利だけど危険、とか?
そうそう。教わってそれ使うだけでいい、じゃダメなの?
それじゃ、教わったことしかできないでしょ
うー
プログラミング言語の裏にある本質を見極めなきゃ
どっかの格闘バカみたい
というわけで次回
< Version 11.21 演算子のオーバーロードの意味 >
につづく!
次回もそういうむつかしい話
タイトルが微妙に哲学っぽい感じ……
 
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
RSSに登録
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
 
このページは、Visual C++ 6.0を用いた C++ 言語プログラミングの解説を行う#pragma twiceの一コンテンツです。
詳しい説明は#pragma twiceのトップページをご覧ください。