Figureクラスで図形描画を仮想関数を用いて演習を行ったが、 課題のテーマとした色を用いたクラスを実装する場合には、様々な方法がある。 レポート課題と取り組まれている中とは思うけど、次のテーマの多重継承の導入として総括する。
また、後半は、UMLの基本を説明する。
色付き図形の実装方法
最初の基本となるFigure(FigureColor)が、色情報を持つ方法。 しかしこの方法は、基底クラスから異なるデータ構造として定義することになるため、 全体のプログラムを書き換えることになる。 この場合、すでにFigure,FigureBox…といったクラスでプログラムを 書いている人がいたら、全面的なプログラム修正が必要となるため、 混乱の元になる。
(( FigureColorが色情報を持つ基底クラス )) class FigureColor { private: int color ; public: FigureColor( int c ) : color( c ) { } virtual void draw( int , int ) = 0 ; } ; // FigureColorから派生 class FigureColorBox : public FigureColor { private: int width , height ; public: FigureColorBox( int w , int h , int c ) { : FigureColor( c ) , width( w ) , height( h ) {} virtual void draw( int , int ) { } } ;
授業で説明した、FigureBoxからFigureBoxColorを派生する方法は、 既存のプログラムの延長で機能を追加できる。このため、既存のコードの 有効利用ができるのが利点。 しかし、FigureBox以外に、FigureCircle,FigureStar,FigureTriangle….といった 様々な派生がすでに存在する時は、色に関するコードが後付なので、 色に関するクラスをさらに作る場合は、色の設定処理が洗練された書き方にできない。
(( Figure→FigureBox→FigureBoxColor )) class Figure { (略) } ; class FigureBox : public Figure { (略) } ; class FigureBoxColor : public FigureBox { private: int color ; public: virtual void draw( int x , int w ) { GWsetpen( ... , color , ... ) ; // ださい FigureBox::draw( x , y ) ; } } ;
多重継承
前のFigureBoxColorの例は、色のクラスが後付なので、色に関する処理が複雑であったとして、 その処理を隠蔽化するにはどうすればよいか? 一つの方法が、多重継承である。
class Figure { (略) } ; // 色を扱うクラス class Color { private: int color ; public Color( int c ) ; void setcolor() { GWsetcolor( ... , color , ... ) ; } } ; // 色無しのクラスはそのまま使える class FigureBox : public Figure { (略) } ; class FigureBoxColor : public FigureBox , public Color { public: FigureBoxColor( int w , int h , int c ) : FigureBox( w , h ) , Color( c ) {} virtual void draw( int x , int y ) { setcolor() ; // Colorのメソッドを使う FigureBox::draw( x , y ) ; } } ;
ただし多重継承は以下の理由から、実装が複雑化することから、Javaなどの言語では別の方法を用いる。
- 継承は、派生したクラスのデータが基底クラスの後ろに繋がる形で実装される。 データ領域の先頭部分は基底クラスのデータ領域であり、基底クラスの参照は極めて単純。 しかし、多重継承を認めると、データ領域の後ろに派生データを追加する方法では、 途中に別の基底クラスのデータ領域を挟み込む形になるため、基底クラスを参照することが複雑になる。
- また、基底クラスに同名のメソッドがあった場合、派生クラスでのメソッド呼び出しでどちらを呼び出すべきか、曖昧になる。
- さらに、ダイヤモンド継承があると、基底クラスのデータが2重化する可能性がある。
(( ダイヤモンド継承 )) 動物クラス[誕生日] / \ 鳥クラス[羽] 哺乳類クラス[手] \ / カモノハシ // 鳥クラスは要素として[誕生日,羽]を持つ // 哺乳類クラスは、[誕生日,手]を持つ // カモノハシクラスは、[誕生日,羽,誕生日,手]を持つ???
UML
UML(Unified Modeling Language)とは、オブジェクト指向で、データ構造や処理の流れを図で表現するための手法として 考えられた。
例えば、処理の流れを図示する場合のフローチャートは、初心者でも分かりやすい。 しかし、長方形のマスの中に複雑な処理を記入するのは困難となる。 改良版として、PADという記法もあるが、あまり普及していない。
歴史的に見れば、 ランボーの提唱したオブジェクトモデル化技法(OMT)、 ブーチがオブジェクト指向設計(OOD)でのBooch法、 ヤコブソンのオブジェクト指向ソフトウェア工学(OOSE)の考え方を元に、 UML(統一モデリング言語)が策定された。
UMLでの図の表現は、データ構造を表現するクラス図、コンポーネント図、オブジェクト図、パッケージ図などがあり、 一方で処理の振舞いを記述する、アクティビティ図、ユースケース図、状態遷移図、相互作用図、シーケンス図などがある。 詳しくは次週の講義にて、説明。