#pragma twice

KAB-studio > プログラミング > #pragma twice > 369 Version 17.14 多態性、多相性

#pragma twice 369 Version 17.14 多態性、多相性

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

 Version 17.14
多態性、多相性

前回まで、ポリモーフィズムの機能について説明してきました
つまり、ポインタを通して仮想関数を呼び出すと、オーバーライドした方
が呼び出される、ってことよね
それが【ポリモーフィズム】っていう機能
でもさ、なんかメリットとか感じないんだけど。これって何に使うの?
今回はその辺も含めて、ポリモーフィズムとは何か、について説明しま

はーい
まず、【ポリモーフィズム】という言葉の意味から。これは英語で
polymorphism と書きます
うぉ英語で見ると難しそう
分けるとすると、 poly-morphism かな
あ、じゃあ発音は、【ポリ・モーフィズム】って感じ?
意識して言うならそうかな。これを分けて説明するとまず poly は
〈多くの〉とか〈複数の〉っていう意味。【ポリゴン】って知ってる?
ゲームの?
そうそう。昔の3Dのゲームってカクカクしていたでしょ
うん、なんかブロックみたいだった
ああいう多面体のことをポリゴンって言うんです
その〈多〉が〈ポリ〉?
そういうこと。あとちょっと化学っぽくなるけど、ポリエチレンとか
ポリプロピレンとか、関連してポリバケツもそうかな
……バケツと〈多〉にどんな関係が?
いやそうじゃなくて材質が……まぁそれはいいや。〈ポリ〉は〈多〉とい
う意味、ということ
じゃあ morphism は?
この語源の morph というのは〈様々な姿のうちのひとつの姿〉っていう
意味。【モーフィング】、って知ってる?
? 聞いたことあるような……
昔はやったんだけど、あるふたつの画像があって、その画像が変わる
映像のことを【モーフィング】( morphing )って言うんです。イメージ検索
してみると分かるかな
あー、これ見たことある。人からゴリラになったりとかそういうのね
これを組み合わせて、 poly-morphism っていうのは〈様々な姿を見せる〉
っていうことを意味するんです
様々な姿……
もうひとつ語源を上げると、たとえば蝶
ちょう、って飛ぶチョウチョのこと?
そうその蝶。蝶って、いもむし、さなぎ、蝶ってさまざまな姿があるで
しょ。そういう、状況に応じて姿が変わっていくことを polymorphism 
って言います
あーいわゆる変態ってやつね
なんでそんなことは知ってるかな……あ、でもそれも関係してるかな。
変態の事を【メタモルフォーゼ)】( metamorphoses って言うんだけど
あ、 morph が入ってる!
そういうこと。様々な姿を見せること、それがポリモーフィズムの語源と
いうことになります
なるほどねー
また、この関係で、日本語では【多態性】(たたいせい)や
【多相性】(たそうせい)と言います
多態性、は、多くの態度を見せる、って分かるけど、多相性、って?
〈相〉?
〈相〉は〈姿形〉って意味。〈人相〉や〈血相〉とか言うでしょ
あー
そういう意味で、多相性は〈様々な姿〉っていう意味になるかな
なるほど。っていうか多態性って最初から言ってくれた方が分かりやすい
と思うんだけど。ぐぐってもその方が多いし
ポリモーフィズムは【ポリモフィズム】とか【ポリモルフィズム】って
表記されることもあるから同じくらいかな。でも言葉的には【多態性】の方
が分かりやすいかもね
んー……で、ポリモーフィズムっていうのがそういう意味だ、っていうの
は分かったけど、いまいち仮想関数とかと継ながらないかな
そうだね、これはプログラムの例で見た方が分かりやすいかな。まず、
以下のように基本クラス CData クラスと派生クラス CDerivedData1 クラス
と CDerivedData2 クラスを用意します

// Data.h

// CData クラス。
class CData
{
public:
    // 仮想関数。
    virtual void Output();
};

// CData クラスの派生クラス1。
class CDerivedData1 : public CData
{
    // オーバーライドします。
    void Output();
};

// CData クラスの派生クラス2。
class CDerivedData2 : public CData
{
    // オーバーライドします。
    void Output();
};


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

#include "Data.h"

// 基本クラスの Output() メンバ関数(仮想関数)。
void CData::Output()
{
    OutputDebugString( "CData::Output()\n" );
}

// 派生クラスの Output() メンバ関数。
// オーバーライドしています。
void CDerivedData1::Output()
{
    OutputDebugString( "CDerivedData1::Output()\n" );
}

// 派生クラスの Output() メンバ関数。
// オーバーライドしています。
void CDerivedData2::Output()
{
    OutputDebugString( "CDerivedData2::Output()\n" );
}

図にするとこうなります

              ┌───────────┐
              │CData クラス          │
              │                      │
              │Output() メンバ関数   │
              └───────────┘
                          △
                          │
            ┌──────┴──────┐
            │                          │
┌─────┴─────┐  ┌─────┴─────┐
│CDerivedData1 クラス  │  │CDerivedData2 クラス  │
│                      │  │                      │
│Output() メンバ関数   │  │ Output() メンバ関数  │
└───────────┘  └───────────┘

基本クラスひとつに派生クラスふたつね
それぞれで仮想関数 Output() メンバ関数
これを、以下のように使用します

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

#include "Data.h"

// CData クラスのポインタを受け取って、
// Output() メンバ関数を呼び出す関数。
void CallOutput( CData *p_pcData )
{
    p_pcData->Output();
}

int WINAPI WinMain
    ( HINSTANCE p_hInstance
    , HINSTANCE p_hPrevInstance
    , LPSTR p_pchCmdLine
    , int p_iCmdShow
    )
{
    // CDerivedData1 クラスの変数を作成します。
    CDerivedData1 cDerivedData1;
    // CallOutput() 関数に渡します。
    CallOutput( &cDerivedData1 );
    // CDerivedData1::Output()

    // CDerivedData2 クラスの変数を作成します。
    CDerivedData2 cDerivedData2;
    // CallOutput() 関数に渡します。
    CallOutput( &cDerivedData2 );
    // CDerivedData2::Output()

    return 0;
}

まず、 CData クラスのポインタを受け取る関数を用意しました

// CData クラスのポインタを受け取って、
// Output() メンバ関数を呼び出す関数。
void CallOutput( CData *p_pcData )
{
    p_pcData->Output();
}

この関数内では、引数で渡されたポインタを通して Output() メンバ関数
を呼び出します
うん、普通ねー
でもこの部分ではポリモーフィズムが働くんです。 CDerivedData1 クラス
の変数を渡した場合は、 CDerivedData1 クラスの Output() メンバ関数が
呼び出されます

    // CDerivedData1 クラスの変数を作成します。
    CDerivedData1 cDerivedData1;
    // CallOutput() 関数に渡します。
    CallOutput( &cDerivedData1 );
    // CDerivedData1::Output()

そか、 CData クラスの Output() メンバ関数が呼ばれるわけじゃないん
だ、オーバーライドされてるから
また、 CDerivedData2 クラスの変数を渡した場合は CDerivedData1 クラス
の Output() メンバ関数が呼び出されます

    // CDerivedData2 クラスの変数を作成します。
    CDerivedData2 cDerivedData2;
    // CallOutput() 関数に渡します。
    CallOutput( &cDerivedData2 );
    // CDerivedData2::Output()

???
というわけで次回に続く!

/*
    Preview Next Story!
*/
ポリモーフィズムって難しそう
こういうのは考え方の問題だからね
ガイネンの話、ってやつ?
そういうこと
でも、なんていうかそれだけじゃないような……
というわけで次回
< Version 17.15 ポリモーフィズムの意味 >
につづく!
考え方っていうか……思想? 宗教??
そういうところもどっかしらあるかもね
 
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
RSSに登録
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
 
このページは、Visual C++ 6.0を用いた C++ 言語プログラミングの解説を行う#pragma twiceの一コンテンツです。
詳しい説明は#pragma twiceのトップページをご覧ください。