VC++MFCでの独自クラス




前提ーMFC独自クラスの創出

普通VC++を使用している人は殆どMFC(MicroSoft Foundation Class)を 利用してプログラムを作成していると思います。なんと言ってもAppWizardや ClassWizardの項目を選択するだけで、90%のコードを自動的に作成して くれること、そしてVBライクなGUIツールを利用できることは大きなメリットで あります。イベントハンドラーに表示・操作方法のコードを書くだけで OKです。 が、しかし、一寸ここで立ち止まって考えてみて下さい。 何か、自分自身がWindowsの枠組みに嵌め込まれているような気がしませんか? 折角覚えたC++のオブジェクト指向言語に関する知識が活かせない。 そもそもInt Mainが有りませんよねぇ。 またクラスもMFCクラスからは継承は出来るが何か自分の手作り感に欠けますよね? ロジック部分のGUIからの分離って?どうしたら良いんだろう、なんて疑問も 浮かびます。 「この為に」MFCとは別にGenericクラスが存在するのです。 はっきり言わせてもらえば、Genericクラス無きMFCプログラムはオブジェクト指向 であるとも、そもそもプログラミングとさえも呼べません。 主体性や独創性をWindows Systemに奪われ、疎外されたプログラマーに成り果てて おるのであります。「かくも」重要なGenericクラスであるにも関わらずVC++の マニュアル、説明本やFAQに作成方法や操作が掲載されることが極めて少ない。 マイクロソフト社以外の人間の知的進歩を妨害するビルゲイツの大いなる 陰謀ではないか? そこで不肖Aranskが超初心者でも理解できる方法をここで伝授致します。 WizardやMFCに関する操作は山のように本が出版されております。またMSDNにも 詳しく説明されておるのでそちらを参考にして下さい。あくまでポイントを GenericクラスをどのようにMFCに組み込むのか?に絞ってご説明致します。 またサンプルはこれ以上簡単な説明は不可能という程、削ぎ落としたもので あります。勿論、実用性も… では、プロジェクトの基本仕様をご説明します。 「Windowsの画面をクリックしたらHello Aransk!と表示します。」 これだけ。 1.新規作成ー>MfcAppWizard(exe.)−>プロジェクト名をbanzaiにして   SDIのスケルトンを作成して下さい。SDIを選択して「次へ」を押し   続け、最後に終了を押せば自動的に作ってくれます。 2.クラスビューを見ると,CAboutDlg,CMainFrame,CBanzaiApp,CBanzaiDoc, CBanzaiViewが並んでいますよね? 3.CBanzaiViewを右クリックします。   イベントハンドラーの追加ー>WM_LBUTTONDOWNを選択ー>追加と編集   4.すると下記部分がコードペインに表示されるので 太字部分を書き込みます。   // CBanzaiView クラスのメッセージ ハンドラ void CBanzaiView::OnLButtonDown(UINT nFlags, CPoint point) { CClientDC dc(this); dc.TextOut(point.x, point.y, "Hello Aransk!"); } デヴァイスコンテキストDCとかthisの説明なんかはマニュアル参照下さい。 ここでビルドと実行してみて下さい。 なんと、画面をクリックする度に畏れ多くも「Hello Aransk!」が表示される ではありませんか?! 申し訳ありません。Genericクラス無しで仕様を完全に満足するものが出来上がって しまいましたぁ。 ここで諦めては貴方は一生Genericクラスを利用できません。 無理やり、かつ、かなり強引に、Genericクラスを活用する方向にもって行きます。 (Aransk得意の力技であります。 6.挿入ー>クラスの新規作成ー>プルダウンからGenericクラスを選択   −>クラス名をGeneにしてー>OK   するとクラスビューの末尾に見事!Geneが追加されます。当たり前ですが… 7.ファイルビューに変えるとソースファイルにGene.cpp及びヘッダーファイルに   Gene.hが追加されておるのがお分かりだと思います。 8.まずはGene.hから、クラス宣言部です。太字部分を記入します。 // Gene.h: Gene クラスのインターフェイス // ////////////////////////////////////////////////////////////////////// #if !defined(AFX_GENE_H__5F2A2250_C759_4A1F_B487_9AF2C28A20B8__INCLUDED_) #define AFX_GENE_H__5F2A2250_C759_4A1F_B487_9AF2C28A20B8__INCLUDED_ #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 class Gene { private: CString str; public: Gene(); void setter(); CString getter(); virtual ~Gene(); }; #endif // !defined(AFX_GENE_H__5F2A2250_C759_4A1F_B487_9AF2C28A20B8__INCLUDED_) ここでCStringが使えることにご注目下さい。文字列操作でこれが使えるか どうかで効率が30%違います。他の部分はコンストラクターやデストラクター を含め自動作成されます。初心者とはいえ、コンストラクターって? なんて質問はやめて下さい。自分でC++本を読んで勉強して下さい。キッパリ また、__5F2A2250_C759_4A1F_B487_9AF2C28A20B8_これ何?なんて質問も やめましょうね。マイクロソフトの人以外にこんな暗号はワカリマセン。(^_^;) ワタクシは単に文字列変数1個とgetter(),setter()を宣言しただけ。 これがオブジェクト指向の原則であります。直接メンバー変数にアクセスできない ようにprivate宣言しております。すべてメンバー関数であるgetter(), setter()経由でこの変数を操作します。これをクラスのカプセル化と称します。 9.次にGene.cppです。関数定義部の記入です。太字部分を記入下さい。 // Gene.cpp: Gene クラスのインプリメンテーション // ////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "banzai.h" #include "Gene.h" #ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[]=__FILE__; #define new DEBUG_NEW #endif ////////////////////////////////////////////////////////////////////// // 構築/消滅 ////////////////////////////////////////////////////////////////////// Gene::Gene() { } Gene::~Gene() { } void Gene::setter() { str = "Hello Aransk!"; } CString Gene::getter() { return str; } これも単にgetter(),setter()の定義を追加しただけです。 これでGenericクラス側の作業は完了しました。 無茶苦茶、楽であります。仕様が簡単だから… 10.先程のCBanzaiViewを再度開いて下さい。その先頭部にGene.hをインクルード    します。 // banzaiView.cpp : CbanzaiView クラスの動作の定義を行います。 // #include "stdafx.h" #include "banzai.h" #include "Gene.h" #include "banzaiDoc.h" #include "banzaiView.h" 太字部分を記入します。 さらに先程開いたOnLButtonDownのメッセージハンドラーに太字部分を 追加修正して下さい。 // CBanzaiView クラスのメッセージ ハンドラ void CBanzaiView::OnLButtonDown(UINT nFlags, CPoint point) { Gene gene; gene.setter(); CString z = gene.getter(); CClientDC dc(this); dc.TextOut(point.x, point.y, z); } "Hello Aransk!"をzに変更することを忘れないようにね。 つまりint MainってWindowsではWin Mainなんですが、MFCでは直接 触れないのであります。MFC構造の中に隠蔽されています。 従ってイベントハンドラーがその代行をしておる次第です。 これをビルトー>実行して下さい。 な、なんと、画面をクリックする度に畏れ多くも「Hello Aransk!」が表示される ではありませんか?! 驚かれましたぁ?こんなに簡単にGenericクラスが利用できるなんて 夢にも思われなかったんじゃないでしょうか? さっきの方が簡単じゃん!<−こんな罰当たりなことを言ってはいけません。 JavaであろうがC++であろうがMainに直接書き込めば、何でも出来るし かつ速いのです。そこをオブジェクト指向言語は「わざわざ」コードを増やし 実行効率を犠牲にしてまで、人間の認知能力に近づけるため、またコードの 再利用性を高めるため、に進歩的?な発達を遂げたのであります。 もし社会の発達に応じて法体系が複雑化しなかったら? 司法に関係する大量の判事、検事、弁護士、法学部の教授、評論家、国会議員、 公設秘書、司法書士、税理士、行政書士、公認会計士、等々、現代の「知的」と 看做されている職業についておられる方々が全滅します。(議員の先生方は除く) 恐るべきことじゃありませんか。 サービス産業化する社会において複雑化は雇用を守る砦であります。 単純化すれば専門家が不要になります。 全ては経済原則によって支配されておるのであります。 プログラム構造も例外ではありません。ホントカ? なお上記プログラムは最新のVC++ドットネット環境ではありません。 基本的にワタクシ新しいものにはすぐ飛びつきません。バグが出尽くした 枯れた環境を好みます。 従ってVC++6.0SP4.0エンタープライズ版であります。勿論、アカデミックパック です。それでもスゴイ出費で涙が出ました。立ち食い蕎麦100杯分! 何故?マイクロソフトはGenericクラスを宣伝しないのか? GenericクラスはMFCの周辺機能であります。セーフティーネットも万全とは 言えません。さらにユーザーが何をやるのか予測がつかないからであります。 MFCの継承クラスであれば、単なる機能追加ですからたかが知れております。 マイクロソフトの気持ちは痛い程良く理解できます。ユーザーはほっとくと 何をしでかすか、特にワタクシのような生齧りが一番ヤバイのであります。 GenericクラスでポインターやC言語のマロックを使いまくって、回復不能の ダメージを起こすのは決まってワタクシのようなユーザーであります。 マクロを消したり、変更したり、好き放題やりまくりますから。 これは私見ですが、プログラマーってのはユーザーを決して信用しません。 何故か?コンピューターはプログラム通り動きますが、人間は何をやり 出すかわかりません。いきなり怒鳴り出してもPCが分かる訳ないっしょ (マイクロソフト様のアカデミックパックを利用させて頂いておる関係上  これ以上の御フザケは…ライセンスを取り消されると困るので)   従って皆様に申し上げます。上記プログラム操作によりパソコンが壊れようが ソフトが消えようがワタクシ一切の責任を負いません。 自らの責任においてリスクを敢然と負う者のみが、自由の天地を切り開く のであります。 目次へ

折角クラスを作ったんだから、継承はどうすれば良いんだ?とのご質問を 予想して以下に簡単なサンプルを記載します。 まずは、プロジェクトの基本仕様をご説明します。 「Windowsの画面をクリックしたらHello Aransk!と表示します。」 これだけ。  もし笑う方があればー>The Evolution of a Haskell Programmer これ笑えるでしょう?全く同じ機能を良くここまでコードを変化させるなって。 Haskellなんて知らんって?何のこっちゃさっぱり分からんって? では、GOFのDesign Patternを読んだ方おられますよね?あれってどこが デザインパターンでどこが機能そのものを実装してるのか?さっぱり 分かりませんでしょう。あまり簡単なサンプルではGOFの連中のプライドが 許さなかったのであります。だから教則本の範囲を超えた実用的なサンプルが 並んでおります。しかし誰もパターンそのものを把握出来ない。 まさに本末転倒でありますまいか? ワタクシ皆様の「ために」敢えてプライドをかなぐり捨てたのであります。 極限のシンプルさと尊いお言葉「Hello Aransk!」の表示だけに絞りこんだので あります。…って、そこまで普通言うか? それはともかく早速本論に…まずはderived ClassをGene2とします。 1.挿入ー>クラスの新規作成ー>プルダウンからGenericクラスを選択   −>クラス名をGene2にしてー>OK   するとクラスビューの末尾にGene2が追加されます。   (クラスを作る度にこの操作をしてMFCに教えてやる必要があります。    ちょっとメンドイけど…) 2.ファイルビューに変えるとソースファイルにGene2.cpp及びヘッダーファイルに   Gene2.hが追加されておるのがお分かりだと思います。 3.まずはGene2.hから、クラス宣言部です。太字部分を記入します。 // Gene2.h: Gene2 クラスのインターフェイス // ////////////////////////////////////////////////////////////////////// #if !defined(AFX_GENE2_H__9C9009D9_8CC2_4EC2_8A2C_07795C2BE2EE__INCLUDED_) #define AFX_GENE2_H__9C9009D9_8CC2_4EC2_8A2C_07795C2BE2EE__INCLUDED_ #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 #include "Gene.h"//Gene.hをインクルードします。 class Gene2 : public Gene /**Geneからのクラス継承です。Javaのextendsより:の方がシンプルです。 Rubyの > はちょっと美的センスに欠ける?最初のRuby本見られました? matzの趣味だってぇ!女性プログラマーがあれでRubyから何人も退いた そうです。  { public: Gene2(); void setter();//setterだけGene2で再定義します。 virtual ~Gene2(); }; #endif // !defined(AFX_GENE2_H__9C9009D9_8CC2_4EC2_8A2C_07795C2BE2EE__INCLUDED_) 4.次にGene2.cppです。関数定義部の記入です。太字部分を記入下さい。 // Gene2.cpp: Gene2 クラスのインプリメンテーション // ////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "banzai.h" #include "Gene2.h"//#include "Gene.h"は不要です。ヘッダーでインクルード済 #ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[]=__FILE__; #define new DEBUG_NEW #endif ////////////////////////////////////////////////////////////////////// // 構築/消滅 ////////////////////////////////////////////////////////////////////// Gene2::Gene2() { } Gene2::~Gene2() { } void Gene2::setter() { str = "Aransk"; } 5.Gene.hとGene.cppを一部下記の通り太字部分に変更します。 // Gene.h: Gene クラスのインターフェイス // ////////////////////////////////////////////////////////////////////// #if !defined(AFX_GENE_H__5F2A2250_C759_4A1F_B487_9AF2C28A20B8__INCLUDED_) #define AFX_GENE_H__5F2A2250_C759_4A1F_B487_9AF2C28A20B8__INCLUDED_ #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 class Gene { protected: CString str;//継承クラスで利用するためprotectedに変更 public: Gene(); void setter(); CString getter(); virtual ~Gene(); }; #endif // !defined(AFX_GENE_H__5F2A2250_C759_4A1F_B487_9AF2C28A20B8__INCLUDED_) // Gene.cpp: Gene クラスのインプリメンテーション // ////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "mouse.h" #include "Gene.h" #ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[]=__FILE__; #define new DEBUG_NEW #endif ////////////////////////////////////////////////////////////////////// // 構築/消滅 ////////////////////////////////////////////////////////////////////// Gene::Gene() { } Gene::~Gene() { } void Gene::setter() { str = "万歳!";//これはあまり意味がある変更とは…(^_^;) } CString Gene::getter() { return str; } 6.最後に先程のCBanzaiViewを再度開いて下さい。その先頭部にGene2.hを インクルードします。 // banzaiView.cpp : CbanzaiView クラスの動作の定義を行います。 // #include "stdafx.h" #include "banzai.h" #include "Gene.h"//Gene2.h経由で、これ無しでも作動しますが… #include "Gene2.h" #include "banzaiDoc.h" #include "banzaiView.h" 太字部分を記入します。 さらにOnLButtonDownのメッセージハンドラーに太字部分を 追加修正して下さい。 // CBanzaiView クラスのメッセージ ハンドラ void CBanzaiView::OnLButtonDown(UINT nFlags, CPoint point) { Gene gene; gene.setter(); CString z = gene.getter(); Gene2 gene2; gene2.setter(); CString w = gene2.getter(); CClientDC dc(this); dc.TextOut(point.x, point.y, z + w); } z + w のプラス記号が使えるところがCStringを使ったメリットであります。 確かにGenericクラスを使用しながらMFCのクラスを利用することに抵抗を 覚える方もおられると思いますが、ワタクシは楽な方を取ります。 使えるものは何でも使う。この精神であります。 じゃぁMFCだけで作れりゃぁ良いじゃないかって? これはあくまでサンプルですから、Linuxを使うときゃぁその時考えれば 良いじゃないかと…。この辺りは好みの問題と言うことで。 ビルドー>実行します。Hello Aransk!がクリックする度に…

クラスのカプセル化ー>継承と説明しましたので、オブジェクト指向3原則の 最後として多態性(ポリモルフィズム)をどうGenericクラスで実現するか その方法だけに絞ってご説明します。そもそも多態性って何?とか、ポインター って何物?とか、仮想(ヴァーチャル)メンバー関数って?とかの初歩的な 質問については山のように…説明本が出ておりますが、正直分かりにくいです。 弊HPのJavaWorkShopでもJavaで説明しております。ご参考にして下さい。 なんせポインターだけで一冊本を書いた人がいますから…。 早速、プロジェクトの基本仕様をご説明します。 「Windowsの画面をクリックしたらHello Aransk!と表示します。」 これだけ。 半ば意地になっておりますので… 1.Gene.hの一部下記の通り太字部分に変更します。Gene.cppは変更無しです。 // Gene.h: Gene クラスのインターフェイス // ////////////////////////////////////////////////////////////////////// #if !defined(AFX_GENE_H__5F2A2250_C759_4A1F_B487_9AF2C28A20B8__INCLUDED_) #define AFX_GENE_H__5F2A2250_C759_4A1F_B487_9AF2C28A20B8__INCLUDED_ #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 class Gene { protected: CString str; public: Gene(); virtual void setter();   /*多態性を利用するには基本クラスのメンバ関数にvirtualアクセス修飾子を    付けます。これだけ…*/ CString getter(); virtual ~Gene(); }; #endif // !defined(AFX_GENE_H__5F2A2250_C759_4A1F_B487_9AF2C28A20B8__INCLUDED_) 2.Gene2.hとGene2.cppは変更ありません。 3.CBanzaiViewの先頭部のインクルードファイルも変更ありません。 4.CBanzaiViewのOnLButtonDownのメッセージハンドラーに太字部分を   追加修正して下さい。 // CBanzaiView クラスのメッセージ ハンドラ void CBanzaiView::OnLButtonDown(UINT nFlags, CPoint point) { Gene gene;  Gene2 gene2;//まず、それぞれのオブジェクトを生成します。   Gene* pGenes [2];//親Geneクラスのポインター配列を2個作成。 pGenes[0] = &gene; pGenes[1] = &gene2;//配列に親、子のオブジェクトのアドレス格納。 for (int i=0; i<=1; i++){ pGenes [i] -> setter(); }//親クラスのポインター配列から親子のメンバー関数を一気に操作可能! CString z = gene.getter(); CString w = gene2.getter(); CClientDC dc(this); dc.TextOut(point.x, point.y, z + w); } ビルドー>実行します。Hello Aransk!がクリックする度に…(-_-;) 多態性は確かにコードがゴチャゴチャします。でも親クラスのポインターに 親と子供のオブジェクトのアドレスを入れることにより、親や子のメンバー 関数定義を知る必要なく操作できる点にあります。 この例では二つですが、たくさんのオブジェクトを扱う場合に威力を発揮します。 例えば、親がたくさんの子供に「起床!」って一声、号令をかけるだけで 子供がベットに寝てようが、布団に寝てようが、ソファーで転寝してようが お構いなしに全員起こせるイメージです。

友人から、「いくらなんでも、前回のコード: Gene gene; Gene2 gene2;//まず、それぞれのオブジェクトを生成します。   Gene* pGenes [2];//親Geneクラスのポインター配列を2個作成。 pGenes[0] = &gene; pGenes[1] = &gene2;//配列に親、子のオブジェクトのアドレス格納。 for (int i=0; i<=1; i++){ pGenes [i] -> setter(); }//親クラスのポインター配列から親子のメンバー関数を一気に操作可能! CString z = gene.getter(); CString w = gene2.getter(); 多態性の説明用とは言えあまりにもゴチャゴチャし過ぎてないか? もしViewのイベントハンドラーの実装者とGeneやGene2のクラス実装者が 違ったりしたら大変だぜぇ〜!」と、まさにポイントをついた批判を浴びせられ、 Aranskとしても「う〜ん!」と考え込んでしまいました。 「よし、初心者にはちっとレベルは高いがこの際、Design Patternまで 説明してしまえ!」と一大決心をしたのであります。ってそんなに オーバーアクションが必要なことでもないんですが… では、デザインパターン説明用プロジェクトの基本仕様から…いくらなんでも もうお分かりですよねぇ?そうです。 「Windowsの画面をクリックしたらHello Aransk!と表示します。」 じゃ〜ん!って何でここまで拘るのかは後述しますので… 今回ご説明するのはMediator Patternです。Gradiatorって映画がラッセルクロー 主演でありました。覚えておられますでしょうか? 無関係です。残念ながら… Mediatorとは仲介者であります。ややこしい仕事は専門家にまかせてしまおう と言う思想から生れたパターンであります。 仲介者となるMediクラスを追加します。 1.挿入ー>クラスの新規作成ー>プルダウンからGenericクラスを選択   −>クラス名をMediにしてー>OK Mediクラスを作成します。    2.ファイルビューに変えるとソースファイルにMedi.cpp及びヘッダーファイルに   Medi.hが追加されておるのがお分かりだと思います。 3.まずはMedi.hから、クラス宣言部です。太字部分を記入します。 // Medi.h: Medi クラスのインターフェイス // ////////////////////////////////////////////////////////////////////// #if !defined(AFX_GENE_H__5F2A2250_C759_4A1F_B487_9AF2C28A20B8__INCLUDED_) #define AFX_GENE_H__5F2A2250_C759_4A1F_B487_9AF2C28A20B8__INCLUDED_ #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 class Medi {   public: Gene(); CString m; //CString mをpublicアクセスで追加します。 virtual ~Gene(); }; #endif // !defined(AFX_GENE_H__5F2A2250_C759_4A1F_B487_9AF2C28A20B8__INCLUDED_) 4.次にMedi.cppです。関数定義部の記入ですが今回はコンストラクターを   使用します。太字部分を記入下さい。 // Medi.cpp: Medi クラスのインプリメンテーション // ////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "banzai.h" #include "Gene2.h"//Gene.hは既にGene2にincludeされているので不要。 #ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[]=__FILE__; #define new DEBUG_NEW #endif ////////////////////////////////////////////////////////////////////// // 構築/消滅 ////////////////////////////////////////////////////////////////////// Medi::Medi() {   Gene gene;  Gene2 gene2;   Gene* pGenes [2]; pGenes[0] = &gene; pGenes[1] = &gene2; for (int i=0; i<=1; i++){ pGenes [i] -> setter(); } CString z = gene.getter(); CString w = gene2.getter();//ここまではView.cppからコピーしただけ!   m = z + w; //mにz,wを代入します。 } Medi::~Medi() { } これでMediクラス側の作業は完了しました。 無茶苦茶、楽でしょう?…(-_-;) 5.CBanzaiViewを開いて下さい。その先頭部にMedi.hをインクルードします。 // banzaiView.cpp : CbanzaiView クラスの動作の定義を行います。 // #include "stdafx.h" #include "banzai.h" #include "Medi.h"//Mediが代表するのでGeneもGene2も不要です。 #include "banzaiDoc.h" #include "banzaiView.h" 太字部分を記入します。 さらにOnLButtonDownのメッセージハンドラーに太字部分を 追加修正して下さい。 // CBanzaiView クラスのメッセージ ハンドラ void CBanzaiView::OnLButtonDown(UINT nFlags, CPoint point) { Medi medi; //Mediクラスのオブジェクトを作りmを呼ぶだけです。 CClientDC dc(this); dc.TextOut(point.x, point.y, medi.m); } 見違える程すっきりしましたねぇ! GeneやGene2は全く変更ありません。 これをビルトー>実行して下さい。 画面をクリックする度に「Hello Aransk!」が表示されます。 皆さんに分かりやすいようにMediator(仲介)パターンとして説明しておりますが、 厳密にGOFパターン分類からするとFacadeパターンの方が適当かも知れません。 言語学的な趣味かも知れませんが、Facade(ファサード)って好きな語彙じゃ ないんです。語源はフランス語です。英語ではファケイドって発音するところを ファサードになっております。つまりフランス語でCの下に髭のついたコムスィ コムサの「サ」です。表とか正面とか、「見かけだけ」とか、を意味する女性名詞? なんですぅ。まだMediatorの方がましかなっと… 分類名なんかはかなり適当ですから…特には拘っておりませんが…って もしデザインパターンにご興味のある方は是非その関係の本をお読みになることを お奨めします。(分かり難い本が多いです…)

前提も含め4回にわたってカプセル化、継承、多態性、デザインパターンと 独自に作成したクラス構造をMFCに追加する方法を述べてまいりました。 MFCのお陰で単にView.cppに: CClientDC dc(this); dc.TextOut(point.x, point.y, "Hello Aransk!"); これだけのコードを追加すれば出来るシンプルな機能ー>「MDIの画面を クリックする度にHello Aransk!が表示」を実現出来ます。 それをわざわざ最後は継承、ポリモルフィズム、ポインター デザインパターンまで使い、クラスを3個も増設し実装しました。 何故か? 理由は三つあります。 1.今回はあくまでGenericクラスの実装方法とクラス構造や関係性を   説明するのが主眼であります。つまり機能や実用面を無意味化すれば   するほど、逆に構造や関係性が明確になります。   機能や実用性は日常的な価値判断です。通常はその構造性や関連性と   一体化して現前しております。それを無意味化=エポケーすることで   より本質的なものを抽出するフッサールの現象学的な手法を用いた次第です。   (フッサールって?なんて教養の無い方はいらっしゃいませんよね?    フッサールはドイツの哲学者です。世界的には既に人気は有りません。    でも日本で竹田先生や西先生が王政復古的に担いではおりますが…)    2.機能や実用性をシンプルに極小固定し、構造性や関連性、重層性を様々に   変化させることにより、実に豊穣な世界が作品の裏で展開されることが   ご理解頂けたのではないかと思います。つまりPerlの創始者である   ラリーウォールがいつも言うところの「There is not only one way    to do it!」をご説明したかったのです。   (厳密に言いますとウォールが言ったのは「There is more than one way    to do it.」です。)   そして下記はMIT的?Schemerの反論です。ご参考まで: "This phrase is often associated with the PerlLanguage. Unlike other languages (notably Scheme), Perl intentionally contains many simple expressions that are equivalent in result. Its inventor, LarryWall,is trained as a linguist. He has this 「crazy」 notion that sometimes another phrasing of a sentence might just make the meaning more clear..."   何故小生はワザワザ「There is not only one way to do it!」と   言い換える必要があったのか?   実はmore than と not onlyの間には超え難い「深淵?」があったのです。   前者は「一つよりも」多いを意味し、後者は「一つだけ」では「ない」こと   を意味します。   従って後者は0をもwayの範疇に含むのです。   いくらやろうとしても「出来ない!」こともありますってぇ。   ー>例えば0で割る…   さらにマイナスも!   ー>やってもやっても返って逆効果!…   スンマセン…ちと、のり過ぎましたぁ  3.閑話休題   最後のデザインパターンの例では、View.cppの実装者はMediしか見えません。   GeneとGene2はMediに隠蔽されています。ただ、Mediのインスタンスを作り   mを呼ぶだけです。何と表示されるのかも知る必要がありません。   この情報の圧縮性をご理解下さい。複雑性の圧縮です。専門家である   Mediにお任せです。ある意味安全性の確保とも言えます。   これがMFCの、いやマイクロソフトの基本思想であります。   MFCの裏にはこのようにユーザーから隠蔽化された知がぎっしり詰まって   おります。知の独占と隠蔽による操作の安全の確保、複雑性の圧縮、同時に   収益基盤の確保を図っているのです。   ソフトはハードとともに我々に対して一定の文化と制度を提供します。   そのコンピュータ文化と制度無しには、その環境に対する人間的な   主体性も成立しないのであります。同時に我々は必然的にその文化と   制度に従属する存在となります。便利であり、簡単であり、安全である、   とは決して無償では成立しないのです。お分かりでしょうか?    MFCにGenericにクラスを追加するとは、プログラマーとしての自由と人間的尊厳を 回復する営為であることを申し上げたかった次第であります。
余談です。「お急ぎでない方用」=「暇人専用?」 上記の例でシンプルなコードから一旦はGenericクラス構造によりコード構成が 複雑化します。そして最後はそれを纏めるクラスMediatorを作ることで 少なくとも、その機能を利用するView.cpp側はシンプル化します。 プログラミングの世界から離れて「この現象」に絞って検証してみましょう。 例えば身近なケースとして、大学の法人化や法科大学院の設置を… (あまり身近じゃない方々もおられるとは思いますが) 人文系や理工系でも、基礎的な学問が整理され、すぐ社会に役立つという 目的で法学部や工学部に予算や人材が集中される傾向にあります。 人文系などは司法試験の合格率で大学が評価されようとしております。 経済、商学部、外国語などはまだましです。落ち込みの激しいのは 文学、哲学、文化人類学であります。西サモア諸島における言語と文化 の変遷(西欧文明との混交的視点より)に関する研究を目的としたフィールド ワーク用の予算が、どれぐらいの規模か?ご存知の方は…なんて居る訳が ありません。つまりそれ程、文化人類学徒は…学徒??? Gacktなら知ってる? (似たようなもんです。) なんと、学問の中心分野から周辺地域に追いやられようとしておる次第であります。 (これまでも文化人類学が学問の中心分野に位置していたとは…  始めから周辺的学問であったとしても…) 西サモア諸島が文化の中心地域とは断言致しません、が、しかし、人類の 原文化形態をこれまで維持してきている数少ない地域ではあります。キッパリ 長々と愚痴をこぼしておりますが、要は何を言いたいのか? 基礎から物事を見直す人間がいなくなったら、テクノラートやビューロクラット のごとき専門家集団ばかりになり、社会的な視野狭窄が発生しますよ! シンプルな問題で当事者が腹を割って話せば済むことを民事訴訟法に 頼るような社会になりますよ。アメリカ社会のように「万人の万人に対する 訴訟世界」を生み出すだけじゃないのでしょうか?と問うておるのであります。 これから法律家が増えます。彼らは食って行かなくてはなりません。 しかも高給を目指す連中が多い?(少なくとも文化人類学専攻者よりは…) 必然的に法律を複雑化し訴訟を増やす圧力となります。 「シンプルなコードを複雑化する圧力になり、かつその複雑化を避けるために さらに物事の本質の隠蔽化が進む…専門家抜きに生きられない社会を生み出し つつあるのではないでしょうか?まさに、MFCのGenericクラスで構成した ような倒錯的な?コード社会を生み出すことにならないでしょうか?」 受験生や学部生の皆さん!文化人類学は決して世俗的圧力にはなりません。 社会的には無害であります。 じゃぁ有用かぁ?とか、高給が保証されるのかぃ?とか、モテルのぉ〜?とか、 そのような皆さんにとって極めて「重要な!」ご質問には文化人類学徒=Gackt! はお応えする文化的慣習を未だ形成していないほど、若い!=未熟?な学問で あります。 前途洋々だって、ホント是非、文化人類学を選択枝の一つに付加されんことを 心より祈念致しましてこの拙い講座を終了致します。 大学法人化の試練に立ち向かわれる文化人類学徒諸兄姉に対して 斯学の一ファンよりの「応援メッセージ」であります。 目次へ