エンタープライズ:特集 2003/09/22 21:29:00 更新
C Magazine

[C Magazine連載]プログラムのレシピ(第2回)
ドローツールを作る (2/6)

C MAGAZINE 2002年10月号より転載

図形の基本クラス
 さて、制作上のポイントのところで触れましたが、図形には多くの共通部分があります。オブジェクト指向プログラミングの一般的な流儀では、共通部分を上位クラス(基底クラス、スーパークラス)にまとめて、共通でない部分を下位クラス(派生クラス、サブクラス)でカスタマイズします。

 図形の場合の共通部分は、四隅の座標、色、フォントといった属性です。これらを図形の上位クラス(ここでは基本クラスと呼びます)で定義しましょう。一方、ポリゴンの頂点やテキストの内容などは非共通部分なので、下位クラスで定義します。

 この構成を図にしたものがFig.3です。基本クラスをDObjectとして、4つの図形クラスをDRectangle、DOval、DPolygon、DTextとしました。ポリゴンクラスは個々の頂点を管理する必要があるので、独自部分として頂点リストを持ちます。また、テキストクラスは内容の文字列を持ちます。

Fig.3
Fig.3 図形クラスの構成

 クラスを設計するときには、まずFig.3のような概念図を描いてみると構成が整理しやすいと思います。UMLを使って描くのもいいでしょう。UMLのクラス図は、Fig.3のようなクラスの継承関係やオブジェクトの参照関係を表現するための記法です。自己流の図に比べると少し手間がかかりますが、人に説明するときには便利です。余裕がある方は勉強しておくといいですね。開発ツールによっては、UMLのクラス図から自動的にクラスの雛ひな型を作ってくれます。

●基本クラスのポインタ配列と仮想関数
 図形クラスの共通属性については、だいたい整理できました。一方、メソッド(動作)に関しても共通のものと共通でないものとがあります。共通のメソッドは、共通属性の取得や設定、描画や当たり判定といったものです。各クラス独自の属性の取得や設定などは、共通でないメソッドになります。

 こういった共通のメソッドは、仮想関数にしておくのが常套じょうとう手段です。それは次のような理由からです。

 基本クラスを継承した矩形や楕円といった図形のポインタ(DRectangle*やDOval*)は、基本クラスのポインタ(DObject*)にキャストすることができます。すると、さまざまな種類の図形を基本クラスのポインタ配列で一括管理できるようになります。

 この状態を図にしたものがFig.4です。矩形や楕円といった図形を、基本クラスのポインタ配列(DObject* array[])で管理します。

Fig.4
Fig.4 ポインタ(DObject*)配列を使った図形の管理

 さて、基本クラスのポインタにキャストしてしまうと、元の図形がわからなくなります。しかし、たとえば描画の際には矩形ならば矩形を、楕円ならば楕円を描画しなければなりません。

 そこで仮想関数の出番です。仮想関数を使えば、基本クラスのポインタに変換したあとでも、元の図形クラスで定義されたメソッド(関数)を呼び出すことができます。C++では、仮想関数の定義にvirtualキーワードを使います。Javaの場合は、もともとすべてのメソッドが仮想関数と同等の動きをするので、とくにキーワードは使いません。

 たとえば描画メソッド(void Paint())を仮想関数(virtual void Paint())にした場合の動作は、Fig.5のようになります。基本クラスのポインタ(DObject*)に変換されていても、元の図形クラスに応じた描画メソッドが呼び出されます。配列にあるすべての図形を描画する場合、呼び出し側の処理は、


  for(int i=0; i<length; i++)
    {array[i]->Paint();
  }

のように単純なループにすることができます。これが、基本クラスのポインタ配列と仮想関数を使うことの利点です。このように、(プログラム実行時の)オブジェクトの種類に応じて実行されるメソッドが変化することを、ポリモーフィズム(多態性)と呼びます。ポリモーフィズムはオブジェクト指向プログラミングの重要な概念です。

Fig.5
Fig.5 仮想関数の呼び出し

●基本クラス(DObject)のプログラム例
 基本クラスをC++でプログラミングしたものがList1です。これはC++Builder 6用のプログラムですが、C++Builderに特有な一部のクラス(TPenやTBrushなど)を除けば、ほかのC++処理系でもほぼ同じプログラムになります。

List1 基本クラス(DObject.h)

// オブジェクト(図形の基本クラス)
class DObject {

protected:

   //====================================== (1)
   // 左上座標とサイズ
   float Left, Top, Width, Height;

   // ペン,ブラシ,フォント
   TPen* Pen;
   TBrush* Brush;
   TFont* Font;

   // 図形の塗りつぶしと開閉
   bool Filled;
   bool Closed;

public:

   //====================================== (2)
   // コンストラクタ,複製
   DObject();
   DObject(DObject* src);
   virtual DObject* Clone();

   //====================================== (3)
   // 属性の取得
   virtual float GetLeft() { return Left; }
   virtual float GetTop() { return Top; }
   virtual float GetWidth() { return Width; }
   virtual float GetHeight() { return Height; }

   //====================================== (4)
   // 属性の設定
   virtual void SetPos(float left, float top);
   virtual void SetRect(TRect rect);
   virtual void SetPenColor(TColor color) { Pen->Color=color; }
   virtual void SetBrushColor(TColor color) { Brush->Color=color; }
   virtual void SetFont(TFont* font) { Font->Assign(font); }
   virtual void SetFontColor(TColor color) { Font->Color=color; }
   virtual void SetFilled(bool filled) { Filled=filled; }
   virtual void SetClosed(bool closed) { Closed=closed; }
   virtual void ChangePenWidth(int d_width) {
       Pen->Width+=d_width; if (Pen->Width<1) Pen->Width=1; }

   //====================================== (5)
   // 描画(通常,当たり判定)
   virtual void Paint(TCanvas* canvas) {};
   virtual void PaintHitArea(TCanvas* canvas, TColor color);

};

 List1-(1)では、Fig.3の基本クラスにあるような属性を定義します。ペン(TPen)は線を描くために、ブラシ(TBrush)は塗りつぶしのために使う属性です。また図形を塗りつぶすかどうかを決めるフラグ(Filled)と、図形(主にポリゴン)を閉じるか開くかを決めるフラグ(Closed)とを用意しました。

 List1-(2)ではコンストラクタを宣言します。引数がないデフォルトコンストラクタと、ほかのインスタンスを元にしてコピーを作るコンストラクタとを作りました。また、オブジェクトを複製するためのCloneメソッドも用意します。Cloneメソッドは、編集操作(切り取り、コピー、貼り付け)を実現するときに役立ちます。

 List1-(3)は属性の取得、List1-(4)は属性の設定です。これらのメソッドは、クラスによってオーバライド(再定義)する可能性があるので、仮想関数にしました。

 List1-(5)は描画用のメソッドです。Paintは通常の描画メソッド、PaintHitAreaはあとで解説する当たり判定用の描画メソッドです。これらのメソッドが呼び出される仕組みは、Fig.5で説明したとおりです。

[C Magazine連載]プログラムのレシピ(第2回)
ドローツールとは
制作上のポイント
図形のクラス設計
図形の基本クラス
矩形クラスと楕円クラス
ポリゴンクラス
テキストクラス
グループ化機能
図形の当たり判定
サンプルプログラムの使い方
おわりに
・実行ファイル/リソース一式(.lzh形式/1.31MB)
・リスト(.lzh形式/3.40KB)

関連リンク
▼C MAGAZINE
▼ひぐぺん工房
▼「デスクトップマスコットを作ろう」紹介ページ
▼「デスクトップマスコットを作ろう」著者ページ

前のページ | 1 2 3 4 5 6 | 次のページ

[松浦健一郎(ひぐぺん工房),JAVA Developer]