1. ホーム
  2. oop

[解決済み] 多重継承の具体的な問題点は何ですか?

2022-07-25 15:56:29

質問

C#やJavaの次のバージョンに多重継承を含めるべきかどうか、人々が常に尋ねているのを目にします。幸運にもこの能力を持っている C++ の人たちは、これは最終的に自分で首を吊るためのロープを誰かに与えるようなものだと言います。

多重継承の何が問題なんだ?具体的なサンプルはあるのでしょうか?

どのように解決するのですか?

最も明白な問題は、関数のオーバーライドに関するものです。

例えば、2つのクラス AB というメソッドを定義しています。 doSomething . ここで、3番目のクラス C を継承した AB をオーバーライドするのではなく doSomething メソッドをオーバーライドしません。

このコードをコンパイラがシードすると...

C c = new C();
c.doSomething();

...どのメソッドの実装を使うべきでしょうか?それ以上の説明がなければ、コンパイラが曖昧さを解決することは不可能です。

オーバーライドの他に、多重継承の大きな問題は、メモリ上の物理オブジェクトのレイアウトです。

C++やJava、C#などの言語では、オブジェクトの種類ごとに固定アドレスベースのレイアウトが作成されます。このようなものです。

class A:
    at offset 0 ... "abc" ... 4 byte int field
    at offset 4 ... "xyz" ... 8 byte double field
    at offset 12 ... "speak" ... 4 byte function pointer

class B:
    at offset 0 ... "foo" ... 2 byte short field
    at offset 2 ... 2 bytes of alignment padding
    at offset 4 ... "bar" ... 4 byte array pointer
    at offset 8 ... "baz" ... 4 byte function pointer

コンパイラが機械語コード(またはバイトコード)を生成するとき、これらの数値オフセットを使用して各メソッドやフィールドにアクセスします。

多重継承はそれを非常に厄介なものにします。

もしクラス C の両方から継承している場合 AB にレイアウトするかどうか、コンパイラは決定しなければならない。 AB の順か BA の順で表示されます。

しかし、今度はあなたが B オブジェクトのメソッドを呼び出しているとします。それは本当にただの B ? それとも、実際には C オブジェクトがポリモーフィックに呼び出され、その B インターフェースを介して、ポリモーフィックに呼び出されるのでしょうか?オブジェクトの実際の ID によって、物理的なレイアウトは異なるでしょうし、呼び出し側で呼び出す関数のオフセットを知ることは不可能です。

この種のシステムを扱う方法は、固定レイアウトのアプローチを捨て、各オブジェクトがそのレイアウトを問い合わせることができるようにすることです の前に 関数を呼び出したり、フィールドにアクセスしたりする前に、各オブジェクトのレイアウトを問い合わせることができます。

つまり...長い話になりますが、コンパイラの作者にとって多重継承をサポートすることは首の痛くなることなのです。Guido van Rossum のような人が Python を設計するとき、あるいは Anders Hejlsberg が c# を設計するとき、多重継承をサポートするとコンパイラの実装が著しく複雑になることを知っており、おそらく彼らはそのコストに見合った利益が得られるとは考えないのです。