多重継承
【英】multiple inheritance
多重継承とは、複数の親クラスを継承するというオブジェクト指向プログラミングのテクニックのことである。
多重継承は、あるクラスが複数の親クラスを継承することで、複数の親クラスの特徴を引き継ぐことである。C++などで可能な方法であり比較的よく利用されている。
多重継承では、機能を組み合わせるという意味では有効であるが、メソッド名の衝突問題や継承関係が複雑になり、クラスの分割や再利用が困難になることで継承の本質から逸脱するという大きな問題も孕んでいる。
C++では、この問題に対して仮想継承の仕組みを適用して回避している。また、多重継承が許されていないJavaでは、インターフェース継承(外延継承)を使うことで多重継承に似たテクニックを適用できる。
継承 (プログラミング)
(多重継承 から転送)
出典: フリー百科事典『ウィキペディア(Wikipedia)』 (2023/10/17 00:49 UTC 版)
コンピュータプログラミングにおける継承(けいしょう、英: inheritance)とは、任意のオブジェクトの特性を、他のオブジェクトの特性の基礎にするためのメカニズムと定義されている。
- ^ MDN contributors (2022年9月17日). "継承とプロトタイプチェーン - JavaScript". developer.mozilla.org. 2022年9月18日閲覧。
- 1 継承 (プログラミング)とは
- 2 継承 (プログラミング)の概要
- 3 カプセル化の可視性と継承の可視性
- 4 関連項目
多重継承
出典: フリー百科事典『ウィキペディア(Wikipedia)』 (2021/12/05 08:46 UTC 版)
「継承 (プログラミング)」の記事における「多重継承」の解説
クラスに複数のスーパークラスを持たせることを多重継承という。単一継承と異なり、多重継承では、スーパークラス上のメンバサーチが複数方向に分かれるので、どのメンバが参照されるのかの把握が困難になるという欠点がある。特にフィールドの多重継承・分散配置は、早期に原則禁止が一般化している。メソッドの方はやむなく許容されたので、メソッド決定順序(MRO)問題が取り沙汰された。MRO問題を解決するために導入されたのが、インターフェースの実装やトレイトのインクルードであり、双方はデータ主体クラスを単一継承にしてメソッド主体クラスを多重継承にするというハイブリッド継承の担い手になった。 また、多重継承上のスーパークラスの重複による菱形継承問題も問題視されるようになっている。菱形継承問題の解決策としては、C++/Eiffel発の仮想継承、Eiffel発のリネーミング、Python発のC3線形化などがある。 多重継承と仮想継承のコーディング例を以下に示す。同一のクラスから継承している複数の派生クラスを多重継承して1つのクラスを作る場合に始めの基底クラスの存在をどうするかによって仮想継承と通常の多重継承の2つに分かれる。 class Base {public: int n;};// 非仮想継承。class DerivedNV1 : public Base { /* ... */ };class DerivedNV2 : public Base { /* ... */ };// 仮想継承。class DerivedV1 : public virtual Base { /* ... */ };class DerivedV2 : public virtual Base { /* ... */ };class DerivedNV : public DerivedNV1, public DerivedNV2 { /* ... */ };class DerivedV : public DerivedV1, public DerivedV2 { /* ... */ };int main() { DerivedNV nv; //nv.n = 0; // 曖昧さが解決できないためコンパイルエラー。 nv.DerivedNV1::n = 0; nv.DerivedNV2::n = 0; DerivedV v; v.n = 0; // コンパイルエラーにはならない。 return 0;} この例のような状態は特に菱形継承(ダイアモンド継承)と呼ばれる。 仮想継承でない場合、DerivedNVのインスタンスにはDerivedNV1の基底のBase::nとDerivedNV2の基底のBase::nという2つのnが別に存在することになる(メンバ関数も同様)。一方、仮想継承した場合、DerivedVのインスタンスにはBaseの部分はただ1つしか存在しない。DerivedV1の基底とDerivedV2の基底が共有されている状態である。 先発OOP言語のC++やEiffelでは実装の多重継承ができたが、後発言語のJavaやC#では実装は単一継承限定にされ、代わりにインターフェースの多重継承(界面の多重継承)が導入されている。なぜなら実装の多重継承はメリットよりもデメリットのほうが多いとみなされたためである。 継承関係が複雑になるため全体の把握が困難になる。 名前の衝突。同じ名前を複数の基底クラスがそれぞれ別の意味で用いていた場合、その両方を派生クラスでオーバーライドするのが困難。 処理系の実装が複雑になってしまう。 仮想継承にしていない場合に同一の基底クラスが複数存在してしまう(これが望ましい場面もあるが)。これの何が問題かというと、最初は仮想継承していなかったものを、後から仮想継承にしたくなったときに、変更点を洗い出すのが大変になるからである。つまり仮想継承を使用するには設計をきちんと行う必要があるということである。 しかしながら多重継承を使う方が直感的になる場合もあるとの主張もあり、どちらが正しいとは言えない状況である。
※この「多重継承」の解説は、「継承 (プログラミング)」の解説の一部です。
「多重継承」を含む「継承 (プログラミング)」の記事については、「継承 (プログラミング)」の概要を参照ください。
- 多重継承のページへのリンク