Le problème le plus évident est celui du remplacement de fonction.
Disons avoir deux classes A
et B
, qui définissent toutes deux une méthode doSomething
. Vous définissez maintenant une troisième classe C
, qui hérite des deux A
et B
, mais vous ne remplacez pas la doSomething
méthode.
Lorsque le compilateur amorce ce code ...
C c = new C();
c.doSomething();
... quelle implémentation de la méthode doit-elle utiliser? Sans plus de précision, il est impossible pour le compilateur de résoudre l'ambiguïté.
Outre le remplacement, l'autre gros problème avec l'héritage multiple est la disposition des objets physiques en mémoire.
Des langages tels que C ++, Java et C # créent une mise en page basée sur une adresse fixe pour chaque type d'objet. Quelque chose comme ça:
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
Lorsque le compilateur génère du code machine (ou bytecode), il utilise ces décalages numériques pour accéder à chaque méthode ou champ.
L'héritage multiple le rend très délicat.
Si la classe C
hérite des deux A
et B
, le compilateur doit décider de mettre en page les données dans l' AB
ordre ou dans l' BA
ordre.
Mais maintenant, imaginez que vous appelez des méthodes sur un B
objet. Est-ce vraiment juste un B
? Ou s'agit-il en fait d'un C
objet appelé polymorphiquement, via son B
interface? En fonction de l'identité réelle de l'objet, la disposition physique sera différente et il est impossible de connaître le décalage de la fonction à appeler sur le site d'appel.
La façon de gérer ce type de système est d'abandonner l'approche de mise en page fixe, permettant à chaque objet d'être interrogé pour sa mise en page avant d' essayer d'appeler les fonctions ou d'accéder à ses champs.
Donc ... longue histoire courte ... c'est une douleur dans le cou pour les auteurs de compilateurs de prendre en charge l'héritage multiple. Ainsi, quand quelqu'un comme Guido van Rossum conçoit python, ou quand Anders Hejlsberg conçoit c #, ils savent que la prise en charge de l'héritage multiple va rendre les implémentations du compilateur beaucoup plus complexes, et vraisemblablement, ils ne pensent pas que l'avantage en vaut le coût.