2021-03-13

『オブジェクト指向入門 第2版』の15章を読んだ

第15章 多重継承

あるクラスが複数の親を持つとき,そのクラスは多重継承されている.例えば,ある会社が持っている飛行機(社用機)をCompanyPlaneクラスで表現することを考える.当然,CompanyPlanePlaneを親に持つ.また,会計士から見れば,CompanyPlaneAsset(資産)でもある.この概念は,ComnapyPlanePlaneAssetを親にすることで表現できる.


CompanyPlanePlaneのインスタンスな気もする.自分だったら,資産クラスに飛行機(社用機)インスタンスを持たせてしまいそう.


別の例として,Numeric(数値)とComparable(比較可能な値)が挙げられる.この二つのクラスを親にすることで,比較可能な何らかの値を表すクラスを自由に作成できる.

特性の改名

2つ以上の親が同じ名前の特性を持つとき,子は特性を改名し,名前の衝突を回避する必要がある.

反復継承

祖先を共有するような継承(継承の関係が菱形になるやつ)を反復継承という.祖先の特性が複数の親から継承されることになるが,その特性が同じ名前である場合,それらはひとつの特性となる.特性が改名されていた場合,それは祖先のオリジナルの特性とは異なるものとなる.以下の例では,pay_feeというひとつの特性を,子孫がpay_french_feepay_us_feeに改名している.

class Driver {
	pay_fee
	...
}
class FrenchDriver extend Driver { ... }
class USDriver extend Driver { ... }
class FrenchUSDriver extend FrenchDriver, USDriver {
  pay_french_fee  // FrenchDriverから継承したpay_feepay_french_feeと改名
  pay_us_fee      // USDriverから継承したpay_feepay_us_feeと改名                                                   
}

複製における衝突・選択

以下のようなクラスを考える.

class A { method_A }
class B extends A {
	method_B // method_Amethod_Bに改名した上,再定義
}
class C extends A { }
class D extends B, C { }

Aでは,特性method_Aが実装されている.Bmethod_Amethod_Bに改名,再定義している.DBCを継承している.

このとき,Dmethod_Bmethod_Aを持つことになる.ここでは,名前の衝突は起こらない.次に,以下のコードを考える.

a: A
d: D
a := d
a.method_A()	// 何が呼び出されるのか?

動的束縛によって,method_Aは動的な型によって適切なものが実行される.しかし,この場合,Dmethod_Aは,Bから継承されたものと,Cから継承されたものの二つ存在するため,どちらを呼び出せば良いのかわからない.このような場合では,Dで,どちらの親から継承された特性を有効にするかを明示しなければならない.


この部分あまり理解できていないんだけど,名前の衝突を回避しても,わざわざ有効な特性を選択しなければならないところに複雑さを感じた.継承するときに,祖先が持つ特性から必要なものを選択するのは大変そう.