#pragma twice

KAB-studio > プログラミング > #pragma twice > 399 Version 18.12 プログラムはクラスの組み合わせ

#pragma twice 399 Version 18.12 プログラムはクラスの組み合わせ

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

 Version 18.12
プログラムはクラスの組み合わせ

前回はエディットボックスとデータのやりとりをするクラスを作ってみま
した
確かにあんな感じにクラス作ると便利……なんだけど、結局プログラムが
移動しただけであまり意味なくない?
そんなことはないよ、クラスや関数という形でプログラムをまとめれば、
それを再利用しやすいからね
どういうこと?
たとえば、 Version 18.10 ( No.397 ) で紹介した、 CEditCtrl クラス
に分ける前のプログラムはこうなっていたでしょ

// = ボタンが押された時のイベントハンドラ。
void CNewCalcDialog::OnEqual()
{
    // 各エディットボックスのウィンドウハンドルを取得します。
    HWND hLeftWnd = GetDlgItem( m_hWnd, IDC_E_LEFT );
    HWND hRightWnd = GetDlgItem( m_hWnd, IDC_E_RIGHT );    ←無駄
    HWND hAnswerWnd = GetDlgItem( m_hWnd, IDC_E_ANSWER );

    // 各エディットボックス用文字列を用意します。
    char pchLeft[256];
    char pchRight[256];                                    ←無駄

    // IDC_E_LEFT と IDC_E_RIGHT の文字列を取得します。
    GetWindowText( hLeftWnd, pchLeft, 255 );
    GetWindowText( hRightWnd, pchRight, 255 );             ←無駄

    // 文字列から数値として取り出すためのストリームを用意します。
    std::istrstream cIStrStreamLeft( pchLeft );
    std::istrstream cIStrStreamRight( pchRight );          ←無駄

    // それぞれ int 型に変換します。
    int iLeft;
    int iRight;                                            ←無駄
    cIStrStreamLeft >> iLeft;
    cIStrStreamRight >> iRight;                            ←無駄
// 以下略

うぉ、無駄ばっか!
この、エディットボックスから入力値を取得する部分って、
IDC_E_LEFT と IDC_E_RIGHT とで同じ処理だから
まったく同じことを二度しなきゃいけない、だから無駄なのね
これを CEditCtrl クラスの GetInt() メンバ関数にまとめると、呼び出す
側はこんなにシンプルになります

// = ボタンが押された時のイベントハンドラ。
void CNewCalcDialog::OnEqual()
{
    // 各エディットボックス用の、 CEditCtrl クラスの変数を
    // 用意します。
    CEditCtrl cEditCtrlLeft( m_hWnd, IDC_E_LEFT );
    CEditCtrl cEditCtrlRight( m_hWnd, IDC_E_RIGHT );
    CEditCtrl cEditCtrlAnswer( m_hWnd, IDC_E_ANSWER );

    // 入力値を取り出します。
    int iLeft = cEditCtrlLeft.GetInt();
    int iRight = cEditCtrlRight.GetInt();
// 以下略

つまりそれって、同じことを何度もしてるところはクラスにしましょう、
ってこと?
そういうこと! 同じ機能をクラスにまとめることで、その機能を簡単に
どこでも使うことができます
だね、 CEditCtrl クラスなら多分これから何度も何度も使いそう
それにプログラムは、〈同じ処理をしている部分〉を何個も作らない方が
いいんです
どゆこと?
一番の理由は、修正が面倒なこと。もしその処理に問題があったら
……全部修正しなきゃいけない
もしクラスにしてひとつにしてあったら
そこ直せばいいだけ。なるほどねー
それに、プログラムが見やすくなる、っていうのもあるかな
見やすくなる?
同じ処理を何度も何度も書いてあると、プログラムが長くなってごちゃご
ちゃしてわかりにくくなるから
それよりもクラスに分けた方が分かりやすい………………ッ
はい火美ちゃん
分かりやすくねー!! クラスに分かれてるとファイルも分かれるから分
かりづらいんだけど
最初はそうだろうね。クラスの関係が頭の中でイメージできないと、むし
ろ分かりづらいかも
うんうん
というわけでクラスを図にしてみましょう
そういう解決策ですか!
今回使用しているクラスは次の3つ

CDialog
CNewCalcDialog
CEditCtrl

これを図にすると、こうなります

┌───────────────────────┐      
│CDialog                                       │
├───────────────────────┤
│ m_pcDialog [static メンバ変数]               │
├───────────────────────┤
│ DispatchDialogProc() [static メンバ関数]     │
│ ~CDialog()                                   │
│ DoModal()                                    │
│ DialogProc() [純粋仮想関数]                  │
└───────────────────────┘
                       △
                       │(継承)
                       │
┌───────────────────────┐      
│CNewCalcDialog                                │
├───────────────────────┤
│ m_hWnd                                       │
├───────────────────────┤
│ DialogProc() [オーバーライド]                │
│ OnOk()                                       │
│ OnEqual()  →→→→→→→→→→→→→→→→→→→→→
└───────────────────────┘     ↓
                                                       ↓
┌───────────────────────┐     ↓(使用)
│CEditCtrl                                     │     ↓
├───────────────────────┤     ↓
│ m_hWnd                                       │     ↓
│ m_bIsError                                   │←←←
├───────────────────────┤
│ CEditCtrl()                                  │
│ GetInt()                                     │
│ SetInt()                                     │
│ IsError()                                    │
└───────────────────────┘

……こうしてみると、結構すっきりしてるかも
機能で分かれているからね。各クラスは、

CDialog          :ダイアログの基本機能
CNewCalcDialog   :NewCalcダイアログのイベント処理
CEditCtrl        :エディットボックスとのデータのやりとり

という感じに処理を分けてあるから
だから分かりやすいんだ
もしこれが、 Version 18.01 ( No.388 ) の時のままで、処理するイベント
がどんどん増えたとしたら……
……どんどん複雑になっちゃうね……
それをクラスに分けることでプログラム全体が機能ごとに分かれるから
プログラム全体が分かりやすくなる!
そういうこと。そこから発展させて、クラスを〈プログラムの部品〉って
考えてみるといいかな
プログラムの部品……つまり、クラスを組み合わせてプログラムを作って
いく、ってこと?
そう、プログラムの中にある機能をそれぞれクラスの中に入れて、それを
くっつけていくことで大きなプログラムを作っていく、それが理想かな
そうすれば部品ごとに分かりやすくなる……
それに、プログラムをクラスに分けることで、クラスを交換するだけで簡
単に修正できるようになったりもするんです
どういうこと?
今回の最初で説明した CEditCtrl クラスを使う前と使った後、を例にし
てみようか。もしここで、エディットボックスを自分で作った特殊なものに
切り替えたとします
うんうん
特殊なものなので、 API が使えません。そうすると修正箇所は……
げ、 GetDlgItem() とか GetWindowText() とか、 SetWindowText() とか
全部変えなきゃいけないってこと?
そういうこと。でも、 CEditCtrl クラスを使っている場合、その特殊な
エディットボックスを使うクラスを用意して、 CEditCtrl クラスと同じ
メンバ関数にすれば……
それなら簡単だね、クラス変えればいいだけだもん。……そっか、そう
やって機能をクラスに分けておけば、交換するだけで簡単に機能を切り替え
られるんだ
これを【疎結合】って言います
そけつごう?
分かりやすく言うと、深く結びついていないってこと。 CEditCtrl クラス
を使う前は、 CNewCalcDialog クラスの OnEqual() メンバ関数から直接 API 
を使用していました。これはつまり、 API との深く結びついていたというこ

これは疎結合じゃない、ってことね
そう、深く結びついていて疎結合じゃないと、切り替える箇所が増えて大
変になります。でも CEditCtrl クラスを使えば、 API の呼び出しまでに
一度メンバ関数っていうクッションがあるから
深く結びつかない、つまり疎結合になるってことね
そうすることで、メンバ関数の名前や引数、戻り値を変えずに中だけ変え
てクラスを作ればいいわけです
……? あのさ、もしかしてそれってオーバーライドとかでできるんじゃ
ない?
そう! 実はオーバーライドにはそういう機能もあるんです。今回の
CDialog クラスと CNewCalcDialog クラスの関係もそうだしね
そういえば継承つかってるね
 CDialog クラスの DialogProc() メンバ関数が、メンバ関数名・引数・
戻り値を決めてくれるから、あとは派生クラスで実装して、使ってる部分、
つまり WinMain() 関数の

    CNewCalcDialog cDialog;  ←←←←←←ここ

を変えれば
それだけで別のダイアログのクラスを使うことができる!
そういうこと。こういうポリモーフィズムの機能は、疎結合をするための
ものって言っても過言じゃないかも
なるほどねー
さて、この章は今回で最後です
げ、もう? 今回は早いね……
今回のこれまでの話が、この章のまとめになるかな
つまり、ダイアログプロシージャに全部書かないで、クラスに分ける、

それを実現するための方法が、 Version 18.03 ( No.390 ) の static 
メンバ関数を使う方法や、 Version 18.04 ( No.391 ) のウィンドウの 
32 ビット整数値を利用する方法になるわけです
そういえばそういうのもあったね
元々、ウィンドウプロシージャは普通の関数しかだめ、っていう話だった
からね
それが、クラスのメンバ関数にすることができれば、ここまで色々と
できるようになる……プログラムがクラスの集まりになる!
そういうこと。ウィンドウプロシージャを普通のメンバ関数にする方法と
クラスを組み合わせてプログラムを作っていく、このふたつをちゃんと
憶えておいてください

/*
    Preview Next Story!
*/
次回は最終回!!
まずこれまでのまとめをします!
8年間ってなげー!!
加えてこれからの方針を説明します
どう勉強すればいいかってこと?
何を勉強すればいいか、ってこと
というわけで次回
< Version 18.13 まとめと、これから。 >
つづく!
何を、って具体的には?
 C++ じゃなく、どの言語を勉強すればいいのかてこと
なんですとー!?
 
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
RSSに登録
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
 
このページは、Visual C++ 6.0を用いた C++ 言語プログラミングの解説を行う#pragma twiceの一コンテンツです。
詳しい説明は#pragma twiceのトップページをご覧ください。