#pragma twice

KAB-studio > プログラミング > #pragma twice > 374 Version 17.19 インターフェイスの使い方

#pragma twice 374 Version 17.19 インターフェイスの使い方

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

 Version 17.19
インターフェイスの使い方

前回は
よく分からなかった!
というわけでちゃんとまとめてみます。まず、ポリモーフィズムの一番良
く使われる場面は?
関数ポインタの代わり!
そう、自分で作った関数を呼び出してもらうためにアドレスを渡すのが
関数ポインタ、それをもう少し分かりやすくしたのが
ポリモーフィズムの機能ってわけね
この部分だけを抜き出してみようか。まずは関数ポインタの場合

■関数ポインタの場合
◇準備
                   (関数Aのアドレスを渡す)
┌──使われる側────┐         ┌────使う側───┐ 
│ ・関数Aを呼び出す関数 ←←←←←←・関数A             │
└───────────┘         └──────────┘

◇使う時
                     (関数Aを呼び出す)
┌──使われる側────┐         ┌────使う側───┐ 
│ ・関数Aを呼び出す関数 →→→→→→・関数A             │
└───────────┘         └──────────┘

つまり、使う側で関数を用意してアドレスを渡しておくと、それを呼び出
してくれるわけね
そういうこと。これをポリモーフィズムで実現すると、こうなります

■ポリモーフィズムの場合
◇準備
               (派生クラスの変数のアドレスを渡す)
┌──使われる側────┐         ┌────使う側──────┐ 
│ ・クラスAの仮想関数を ←←←←←←・クラスAの派生クラス。   │
│   を呼び出す関数     │         │  仮想関数をオーバーライド│
└───────────┘         └─────────────┘

◇使う時
               (クラスAの仮想関数を呼び出す)
┌──使われる側────┐         ┌────使う側──────┐ 
│ ・クラスAの仮想関数を →→→→→→・クラスAの派生クラス。   │
│   を呼び出す関数     │         │  仮想関数をオーバーライド│
└───────────┘         └─────────────┘

あれ、こう比べてみるとだいぶ構造が違うような……
ポリモーフィズムの場合、まずクラスAというものを〈使われる側〉で用
意しておく必要があります。使う側は、その派生クラスを作って、仮想関数
をオーバーライドします

     ┌───── クラスA──────┐ 
     │・仮想関数                    │
     └───────────────┘
                     △
                     │
                     │
     ┌───────┴───────┐ 
     │・仮想関数(オーバーライド)    │
     └── クラスAの派生クラス───┘

このオーバーライドした仮想関数が、関数ポインタの時の関数Aに当たり
ます
つまりこれが〈使われる側〉から呼び出されるわけね
もうひとつ重要な点が、使う側は〈クラスAの派生クラス〉の変数を作っ
て、そのアドレスを渡すっていう点
関数ポインタの時は関数のアドレス、ポリモーフィズムの時はクラスの
変数
実はこれが重要。関数の時には関数を渡せるだけ、つまり変数は渡せない
んです
そっか、関数はグローバル変数使わなきゃいけないけど、クラスの変数な
らメンバ変数で渡せる!
そういうこと。つまり、関数ポインタの機能をバージョンアップしたもの
がポリモーフィズム、っていうことが言えるかな
便利になったわけねー。複雑になったけど……
確かに……。さて、話を戻してインターフェイスについて
あーそういえば
上の例で言うと、前回の DoBubbleSortUseComapre() 関数が〈使われる側〉
の〈クラスAの仮想関数をを呼び出す関数〉に当たります

// ソートを行う関数です。
void DoBubbleSortUseComapre
    ( int *p_piAry, int p_iSize, CComparetor *p_pcComparetor )
// CComparetor クラスの仮想関数 CompareTo() メンバ関数を呼び出します

この第3引数に CComparetor クラスの派生クラス、つまり 
CIntComparetor クラスの、変数のアドレスを渡すと、ポリモーフィズムが
効いて、オーバーライドしてる CompareTo() メンバ関数が呼び出される、
っていう仕組みね
そういうこと。で、ここでもう一度さっきの図を振り返ってみます

◇準備
               (派生クラスの変数のアドレスを渡す)
┌──使われる側────┐         ┌────使う側──────┐ 
│ ・クラスAの仮想関数を ←←←←←←・クラスAの派生クラス。   │
│   を呼び出す関数     │         │  仮想関数をオーバーライド│
└───────────┘         └─────────────┘

左が DoBubbleSortUseComapre() 関数、右が CIntComparetor クラスと
CompareTo() メンバ関数だね
この矢印の部分、右から左に CIntComparetor クラスの変数のアドレスを
渡す箇所が DoBubbleSortUseComapre() 関数の第3引数になります

// ソートを行う関数です。
void DoBubbleSortUseComapre
    ( int *p_piAry, int p_iSize, CComparetor *p_pcComparetor )
                                                  ↑
                    ここから派生クラスの変数のアドレスを渡します

つまり、この第3引数が、〈呼び出してもらうメンバ関数を持つクラス〉
の変数を渡す〈受付〉になっている、というわけ
受付……
さっきの図で言うと、この受付部分が

                        ↓ここ
┌──使われる側────┐         ┌────使う側──────┐ 
│ ・クラスAの仮想関数を ←←←←←←・クラスAの派生クラス。   │
│   を呼び出す関数     │         │  仮想関数をオーバーライド│
└───────────┘         └─────────────┘

になります。つまり、この部分が〈使われる側〉と〈使う側〉の接続口に
なっているわけです
確かにここで継ながってるね
で、これをいきなりですがパソコンとプリンタに置き換えます
パソコンとプリンタ???

┌──パソコン─────┐         ┌─プリンタ──────┐ 
│ ・印刷の命令←←←←←←←←←←←・印刷する機能        │
│   を行うアプリ       │         │                      │
└───────────┘         └───────────┘

あ、なんか似てる
これって似てるでしょう。プリンタはパソコンにケーブルで継なぎます。
パソコンはプリンタに対して印刷の命令を出すことで印刷します。この時、
プリンタはどんなメーカーのどんな機種でも印刷できるでしょ?
うん、プリンタのアイコン押せば印刷できるもんね。あ、それって
ポリモーフィズムってこと?
そういうこと! つまり、あらゆるプリンタは〈プリンタの基本命令〉を
持っていて、パソコンに接続することでパソコンはその命令を送るだけで
どんなプリンタでも印刷できるわけです
なるほどねー、〈プリンタの基本命令〉が基本クラスの仮想関数で、それ
ぞれのプリンタの印刷機能が派生クラスでオーバーライド、ってわけね。確
かにポリモーフィズムしてる
で、このケーブル接続用コネクタを、専門用語で【インターフェイス】っ
て言います

                        ↓インターフェイス
┌──パソコン─────┐         ┌─プリンタ──────┐ 
│ ・印刷の命令←←←←←←←←←←←・印刷する機能        │
│   を行うアプリ       │         │                      │
└───────────┘         └───────────┘

おー、つまりこのインターフェイスの部分に当たるから、基本クラスの
ことをインターフェイス、って言ってるんだ
そういうこと。こんな感じに、使う側と使われる側の接続部分になるのが
インターフェイス、というわけです
なるほどねー
ただし!
ただし?
全部の基本クラスがインターフェイスっていうわけじゃないんです。
インターフェイスは、次のようなクラスのことを指します

・基本クラスは持たない(持つとしてもインターフェイスに限る)
・メンバ変数を持たない
・メンバ関数は純粋仮想関数のみ

つまり前回の CComparetor クラスはインターフェイスってわけね

// 比較用クラスの基本クラス。
class CComparetor
{
public:
    // 比較用メンバ関数。純粋仮想関数です。
    virtual bool CompareTo( int p_iL, int p_iR ) = 0;
};

でもなんでこういうルールがあるの?
なぜかっていうと、中身があっちゃいけないから
中身?
パソコンとプリンタの例で言うと、インターフェイスは〈プリンタの機能〉
を持っていちゃいけない、ってこと
あ、なるほど。インターフェイスは接続口でプリンタじゃないから、機能
があっちゃいけないんだ
この CComparetor クラスの場合も、このクラスは比較機能とかは全く
持っていません。ただ、 CompareTo() メンバ関数を呼び出すための接続口
としてのみ機能します
だからインターフェイス、っていうわけね
まぁもっとも、こういうクラスをインターフェイスって呼んでいる、って
いうだけで、普通のクラスなんかと大きな違いはないんだけどね
それじゃ意味ないじゃん

/*
    Preview Next Story!
*/
おー、図にしてなんとか分かってきた感じ
見て分かるっていうのは重要かもね
まぁテキストじゃ限界あるだろうけどねー
確かにね、アスキーアートまで行くと環境によっては見られないし
やっぱりメルマガじゃ限界あるんじゃない?

というわけで次回
< Version 17.20 インターフェイスを戻り値にする >
につづく!
さっきのプリンターとかも、あんな四角じゃいまいちだし〜
http://images.google.co.jp/images?q=%E3%83%97%E3%83%AA%E3%83%B3%E3%82%BFッ
うわ力業で来た!
 
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
RSSに登録
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
 
このページは、Visual C++ 6.0を用いた C++ 言語プログラミングの解説を行う#pragma twiceの一コンテンツです。
詳しい説明は#pragma twiceのトップページをご覧ください。