Il existe un certain nombre de problèmes liés à l'héritage multiple lorsqu'il est utilisé avec des classes complètes, mais ils tournent tous autour de l' ambiguïté .
L'ambiguïté se manifeste de différentes manières:
- Si vous avez deux classes de base avec le même champ
x
et que le type dérivé demande x
, que obtient-il?
- Si les deux
x
variables ont des types incongruents, vous pouvez en déduire.
- S'ils sont du même type, vous pouvez essayer de les fusionner dans la même variable.
- Vous pouvez toujours les exposer sous forme de noms qualifiés étranges.
- Si vous avez deux classes de base avec la même fonction
f
avec des signatures identiques, et que quelqu'un appelle f
, qui appelle?
- Et si les deux classes de base partagent un autre ancêtre virtuel commun (le problème de diamant).
- Que se passe-t-il si la fonction a des signatures différentes, mais compatibles?
- Lorsque vous construisez une classe avec deux classes de base, quel constructeur de ces classes de base est appelé en premier? Lorsque vous détruisez l'objet, qui est tué?
- Lorsque vous disposez l'objet en mémoire, comment le faites-vous de manière cohérente?
- Comment gérez-vous tous ces cas avec 3 classes de base? dix?
Et cela ne tient pas compte d'éléments tels que la répartition dynamique, l'inférence de type, la correspondance de modèle et d'autres éléments moins connus qui deviennent plus difficiles à gérer lorsque le langage prend en charge l'héritage multiple de classes complètes.
Les traits ou mix-ins (ou interfaces, ou ...) sont tous des constructions qui limitent spécifiquement les capacités d'un type afin qu'il n'y ait aucune ambiguïté. Ils possèdent rarement quelque chose eux-mêmes. Cela permet d’aplanir la composition des types car il n’ya pas deux variables ou deux fonctions ... il existe une variable et une référence; une fonction et une signature. Le compilateur sait quoi faire.
L’autre approche couramment adoptée consiste à obliger l’utilisateur à "construire" (ou à mélanger) son type, un à la fois. Au lieu que les classes de base soient des partenaires égaux dans le nouveau type, vous ajoutez un type à un autre, en remplaçant tout ce qui y figurait (généralement avec une syntaxe facultative pour renommer et / ou exposer à nouveau les bits remplacés).
Y a-t-il quelque chose qui n'est pas possible avec mixins / traits mais possible avec l'héritage multiple de style C ++?
Selon la langue, il devient généralement difficile ou impossible de fusionner les implémentations de fonctions et le stockage des variables de plusieurs classes de base et de les exposer dans le type dérivé.
Est-il possible de rencontrer des problèmes de diamants avec eux?
Parfois, des variations moins graves apparaîtront en fonction de votre langue, mais généralement pas. L’essentiel des traits est de briser ce type d’ambiguïté.