エンタープライズ:特集 | 2003/09/22 21:29:00 更新 |
[C Magazine連載]プログラムのレシピ(第2回)
ドローツールを作る (2/6)
C MAGAZINE 2002年10月号より転載
図形の場合の共通部分は、四隅の座標、色、フォントといった属性です。これらを図形の上位クラス(ここでは基本クラスと呼びます)で定義しましょう。一方、ポリゴンの頂点やテキストの内容などは非共通部分なので、下位クラスで定義します。 この構成を図にしたものがFig.3です。基本クラスをDObjectとして、4つの図形クラスをDRectangle、DOval、DPolygon、DTextとしました。ポリゴンクラスは個々の頂点を管理する必要があるので、独自部分として頂点リストを持ちます。また、テキストクラスは内容の文字列を持ちます。
クラスを設計するときには、まずFig.3のような概念図を描いてみると構成が整理しやすいと思います。UMLを使って描くのもいいでしょう。UMLのクラス図は、Fig.3のようなクラスの継承関係やオブジェクトの参照関係を表現するための記法です。自己流の図に比べると少し手間がかかりますが、人に説明するときには便利です。余裕がある方は勉強しておくといいですね。開発ツールによっては、UMLのクラス図から自動的にクラスの雛ひな型を作ってくれます。
●基本クラスのポインタ配列と仮想関数 こういった共通のメソッドは、仮想関数にしておくのが常套じょうとう手段です。それは次のような理由からです。 基本クラスを継承した矩形や楕円といった図形のポインタ(DRectangle*やDOval*)は、基本クラスのポインタ(DObject*)にキャストすることができます。すると、さまざまな種類の図形を基本クラスのポインタ配列で一括管理できるようになります。 この状態を図にしたものがFig.4です。矩形や楕円といった図形を、基本クラスのポインタ配列(DObject* array[])で管理します。
さて、基本クラスのポインタにキャストしてしまうと、元の図形がわからなくなります。しかし、たとえば描画の際には矩形ならば矩形を、楕円ならば楕円を描画しなければなりません。 そこで仮想関数の出番です。仮想関数を使えば、基本クラスのポインタに変換したあとでも、元の図形クラスで定義されたメソッド(関数)を呼び出すことができます。C++では、仮想関数の定義にvirtualキーワードを使います。Javaの場合は、もともとすべてのメソッドが仮想関数と同等の動きをするので、とくにキーワードは使いません。 たとえば描画メソッド(void Paint())を仮想関数(virtual void Paint())にした場合の動作は、Fig.5のようになります。基本クラスのポインタ(DObject*)に変換されていても、元の図形クラスに応じた描画メソッドが呼び出されます。配列にあるすべての図形を描画する場合、呼び出し側の処理は、
のように単純なループにすることができます。これが、基本クラスのポインタ配列と仮想関数を使うことの利点です。このように、(プログラム実行時の)オブジェクトの種類に応じて実行されるメソッドが変化することを、ポリモーフィズム(多態性)と呼びます。ポリモーフィズムはオブジェクト指向プログラミングの重要な概念です。
●基本クラス(DObject)のプログラム例
List1-(1)では、Fig.3の基本クラスにあるような属性を定義します。ペン(TPen)は線を描くために、ブラシ(TBrush)は塗りつぶしのために使う属性です。また図形を塗りつぶすかどうかを決めるフラグ(Filled)と、図形(主にポリゴン)を閉じるか開くかを決めるフラグ(Closed)とを用意しました。 List1-(2)ではコンストラクタを宣言します。引数がないデフォルトコンストラクタと、ほかのインスタンスを元にしてコピーを作るコンストラクタとを作りました。また、オブジェクトを複製するためのCloneメソッドも用意します。Cloneメソッドは、編集操作(切り取り、コピー、貼り付け)を実現するときに役立ちます。 List1-(3)は属性の取得、List1-(4)は属性の設定です。これらのメソッドは、クラスによってオーバライド(再定義)する可能性があるので、仮想関数にしました。 List1-(5)は描画用のメソッドです。Paintは通常の描画メソッド、PaintHitAreaはあとで解説する当たり判定用の描画メソッドです。これらのメソッドが呼び出される仕組みは、Fig.5で説明したとおりです。
関連リンク |
[松浦健一郎(ひぐぺん工房),JAVA Developer]