#pragma twice

KAB-studio > プログラミング > #pragma twice > 219 Version 11.19 オーバーロード関数を作ってみよう

#pragma twice 219 Version 11.19 オーバーロード関数を作ってみよう

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

 Version 11.19
オーバーロード関数を作ってみよう

今回はオーバーロードについて見てみます
オーバーロードって前にやったね
 Version 8.11 ( No.153 ) だね。オーバーロードそのものについては
そっちで解説してるからいいとして、今回は
作ってみる?
そゆこと。まずは簡単な例を見てみます

// オーバーロードしたメンバ関数を持つクラス。
class CHasOverload
{
public:
    // メンバ関数1。
    void Overloaded()
    {
        TRACE( "Overloaded()\n" );
    }

    // メンバ関数2。
    void Overloaded( int p_i )
    {
        TRACE( "Overloaded( %d )\n", p_i );
    }
};

 Overloaded() ってメンバ関数がふたつあるから、これがオーバーロード
してるんだね
そう。戻り値が同じで、引数が違うメンバ関数が、オーバーロードされた
メンバ関数。これの使用例はこんな感じ

void Use_CHasOverload()
{
    CHasOverload cHasOverload;
    cHasOverload.Overloaded();
    // Overloaded()
    cHasOverload.Overloaded( 100 );
    // Overloaded( 100 )
}

引数があるのとないのとで別のが呼ばれるわけね
これは一番わかりやすい例。引数の数が違うから、どっちが呼ばれるかっ
ていうのは一目瞭然だからね
そか、引数の数が同じで、型が違うっていうのもオーバーロードなんだ
というわけでその例

// オーバーロードしたメンバ関数を持つクラス2。
class CHasOverload_SameType
{
public:
    // メンバ関数1。
    void Overloaded( LPCTSTR p_pch )
    {
        TRACE( "Overloaded( %s )\n", p_pch );
    }

    // メンバ関数2。
    void Overloaded( int p_i )
    {
        TRACE( "Overloaded( %d )\n", p_i );
    }
};

上は文字列で、下は整数ね
使用例はこんな感じ

void Use_CHasOverload_SameType()
{
    CHasOverload_SameType cHasOverload;
    cHasOverload.Overloaded( "テスト" );
    // Overloaded( テスト )
    cHasOverload.Overloaded( 100 );
    // Overloaded( 100 )
}

なるほど、文字列を渡すか、数値を渡すかでどっちの関数が呼ばれるかが
決まるわけねー、これは便利かも
ただ、この自動的に決まる、っていうのは実は危険な面もあるんです
危険?
たとえば、文字列が NULL だった場合

void Use_CHasOverload_SameType()
{
    CHasOverload_SameType cHasOverload;
    cHasOverload.Overloaded( NULL );
    // Overloaded( 0 )
    cHasOverload.Overloaded( 100 );
    // Overloaded( 100 )
}

……あれ? もしかして両方とも int の方が呼ばれてる?
そうなんです。  Version 5.11 ( No.076 ) で教えたように、 NULL は数
字の 0 だから int の方が呼ばれちゃうんです
え?  NULL ってアドレスの 0 ってことじゃなかったの?
さっきの No.076 でも触れてるけど、 NULL って、ホントの数字の 0 な
んです
えーでもさ

    int *pi = 0x10000000;

みたいに、ポインタにアドレスの数字って直接入れられないよね
うん、ダメだよ、コンパイルエラーになるから。ところが、実は〈 0 だ
けはどんなポインタにも入れることができる〉っていう特例があるんです
ず、ずるい……
確かにね。だからこそ、上のような問題が出てくるわけ
あ、やっぱ問題なんだ
そう。だから、本当は数字と文字列でオーバーロードするのは危険なこと
なんです。結構多いけどね
多い?
 CString でもしてるし

 No.076 で〈 NULL じゃなくて 0 って書く人もいる〉のは、そういう紛
らわしさをできるだけ取り除くためなんです
そか、上の例でも NULL じゃなくて 0 ならわかるもんね
あと、オーバーロードしてる関数は、あまり動作を変えないようにするの
がコツかな
どーゆーこと?
上の例だとどっちも TRACE() で出してるだけだけど、これがもし、片方
は TRACE() でもう片方はファイルに出力してたら
げ、それはヤダね
だから、オーバーロードは〈引数の型が違っても同じ結果になる〉ってい
う場合にするのがいいと思うよ
結果が違う場合は?
メンバ関数の名前を変えればいいでしょ
あ、そっか
最後に、オーバーロードした関数の戻り値について。オーバーロードした
時にはそれぞれ別の戻り値の型にすることができます

// オーバーロードしたメンバ関数を持つクラス3。
class CHasOverload_OtherReturn
{
public:
    // メンバ関数1。
    void Overloaded( LPCTSTR p_pch )
    {
        TRACE( "Overloaded( %s )\n", p_pch );
    }

    // メンバ関数2。
    int Overloaded( int p_i )
    {
        TRACE( "Overloaded( %d )\n", p_i );
        return p_i;
    }
};

片方は void でもう片方は int ね
使う場合にはこんな感じ

void Use_CHasOverload_OtherReturn()
{
    CHasOverload_OtherReturn cHasOverload;
    cHasOverload.Overloaded( "テスト" );
    // Overloaded( "テスト" )
    int i = cHasOverload.Overloaded( 100 );
    // Overloaded( 100 )
    TRACE( "%d\n", i );
    // 100
}

もし文字列の方で int を受け取ろうとしたら?
そうするとコンパイルエラーになります

    int i = cHasOverload.Overloaded( "テスト" );
    // error C2440: 'initializing' : 
    // 'void' から 'int' に変換することはできません。
    // void 型の式は他の型へ変換できません。

へー
これはとっても重要なこと。実は、どの関数が呼ばれるかは引数でしか決
められないんです。言い換えると、戻り値でオーバーロードすることはでき
ないってこと

たとえば

// オーバーロードしたメンバ関数を持つクラス4。
class CHasOverload_OtherReturn_Bad
{
public:
    // メンバ関数1。
    void Overloaded()
    {
        TRACE( "Overloaded()\n" );
    }

    // メンバ関数2。
    int Overloaded()
    {
        TRACE( "Overloaded()\n" );
        return 100;
    }
};

引数がなくて、戻り値が void と int ……あ、戻り値でオーバーロード
ってこういうことね
これをビルドしてみると
げ、コンパイルエラー出まくり

error C2556: 
'int __thiscall B1::CHasOverload_OtherReturn_Bad::Overloaded(void)'
 : オーバーロード関数の戻り値は異なっていますが、
引数リストは同一です。

というわけで、戻り値だけ変えたり、戻り値でどの関数を呼ぶか決めさせ
たりっていうのはできません
ちょっと不便かも〜

/*
    Preview Next Story!
*/
便利だけど危険、って難しいね
これからはそういうの増えてくからね
むむむ
でもそういう世界に踏み込むと、一人前のプログラマーって言えるかも
い、いつのまにそんなとこまで???
遠回りしたけど結構身に付いてると思うよ
へ〜
というわけで次回
< Version 11.20 演算子をオーバーロードしよう >
につづく!
でもまだ半分も教えてないけど
げ!
 
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
RSSに登録
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
 
このページは、Visual C++ 6.0を用いた C++ 言語プログラミングの解説を行う#pragma twiceの一コンテンツです。
詳しい説明は#pragma twiceのトップページをご覧ください。