ホーム » スタッフ » 斉藤徹 » 多重継承とUMLの導入

2015年7月
« 6月   8月 »
 1234
567891011
12131415161718
19202122232425
262728293031  

最近の投稿(電子情報)

アーカイブ

カテゴリー

多重継承とUMLの導入

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での図の表現は、データ構造を表現するクラス図、コンポーネント図、オブジェクト図、パッケージ図などがあり、 一方で処理の振舞いを記述する、アクティビティ図、ユースケース図、状態遷移図、相互作用図、シーケンス図などがある。 詳しくは次週の講義にて、説明。