継承 (プログラミング)
ミックスイン(Mix-in)は、多重継承問題の解決策を発端にしたもう1つの継承方法論である。メソッドの集合体を継承することで、その機能をクラスに注入することを目的にしており、メソッド集合体とクラスの間には汎化/特化の関係がないままで、多重継承を前提にしている。そのメソッド集合体はトレイトとされることが多く、他にモジュール、プロトコル、ロールといった形態もある。トレイトの継承はインクルードと呼ぶのが好まれ多重継承前提である。ミックスインはそれらをひっくるめた方法論としての用語になっている。
界面継承のインターフェース(抽象メソッドをまとめたクラス)と、Mix-in継承のトレイト(独立メソッドをまとめたモジュール)は双方とも多重継承前提なのでよく対比されて説明される。双方の違いを列挙すると以下のようになる。
ここでのサブタイピングは、親オブジェクトに対する子オブジェクトの安全な代替/代入(substitute)を保証する継承という意味で使われている。それに対してのただの継承は、親オブジェクトの特性をただ引き継ぐことに専念しており、安全な代替/代入には無関心である。たとえ話としては、親の白黒映画をカラー映画化するのが代替可能なサブタイピングであり、親の白黒映画をメディアミックス的グッズ販売につなげるのが代替不可な継承になる。継承に代入可能性(substitutability)を順守させてサブタイピングにすることを提唱しているのが、リスコフの置換原則である。
継承と対比される概念にコンポジション (合成)(英語版)がある。継承のサブタイピング用法の上位概念と下位概念(Is-a)に対して、合成は(Has-a)であるが、継承の非サブタイピング用法では、スーパークラスとサブクラスの関係が(Is-aでもHas-aでもない)の関係になることがしばしばあるので、それと合成との使い分けが重視されるようになっている。
クラスに複数のスーパークラスを持たせることを多重継承という。単一継承と異なり、多重継承では、スーパークラス上のメンバサーチが複数方向に分かれるので、どのメンバが参照されるのかの把握が困難になるという欠点がある。特にフィールドの多重継承・分散配置は、早期に原則禁止が一般化している。メソッドの方はやむなく許容されたので、メソッド決定順序(MRO)問題が取り沙汰された。MRO問題を解決するために導入されたのが、インターフェースの実装やトレイトのインクルードであり、双方はデータ主体クラスを単一継承にしてメソッド主体クラスを多重継承にするというハイブリッド継承の担い手になった。
また、多重継承上のスーパークラスの重複による菱形継承問題も問題視されるようになっている。菱形継承問題の解決策としては、C++/Eiffel発の仮想継承、Eiffel発のリネーミング、Python発のC3線形化などがある。
多重継承と仮想継承のコーディング例を以下に示す。同一のクラスから継承している複数の派生クラスを多重継承して1つのクラスを作る場合に始めの基底クラスの存在をどうするかによって仮想継承と通常の多重継承の2つに分かれる。
この例のような状態は特に菱形継承(ダイアモンド継承)と呼ばれる。
仮想継承でない場合、DerivedNVのインスタンスにはDerivedNV1の基底のBase::nとDerivedNV2の基底のBase::nという2つのnが別に存在することになる(メンバ関数も同様)。
継承は、他のオブジェクトの特性(データ・手続き・関数・定数・アノテーションなど)を引き継ぐという概念であり、引き継いだオブジェクトがどのような性質を持ち、どのように振る舞うのかは全くの任意になる。引き継ぎかたは、リクエストされた特性をそのオブジェクトが持たない場合は、自動的に上位オブジェクトの方でサーチするという方式が一般的であり、これは暗黙の委譲(delegation)ベースとも呼ばれる。他には、インスタンス化時にその型の継承チェーンを走査してその全要素を集めて同名重複要素を解決して1つの実体を生成するという方式もあり、これは連結(concatenation)ベースとも呼ばれる。
他オブジェクトの特性を引き継ぐという概念は、それに新しい特性群を付け足しての手軽なオブジェクトの機能拡張と、引き継がれる共通の特性群を上位ノードにしたオブジェクトの分類体系化をもたらしている。これは差分プログラミングとも呼ばれ、プログラムの再利用性と保守性を高めるとされている。
継承(inheritance)とサブタイピング(subtyping)は混同されやすい。