C ++ a un héritage multiple simple, de nombreuses conceptions de langage l'interdisent comme dangereux. Mais certaines langues comme Ruby et PHP utilisent une syntaxe étrange pour faire la même chose et appellent cela mixins ou traits. J'ai souvent entendu dire que les mixins / traits sont plus difficiles à abuser qu'un simple héritage multiple.
Qu'est-ce qui les rend moins dangereux? Y a-t-il quelque chose qui n'est pas possible avec mixins / traits mais possible avec l'héritage multiple de style C ++? Est-il possible de rencontrer le problème du diamant avec eux?
Cela semble être comme si nous utilisions des héritages multiples tout en prétextant que ce sont des mixins / traits afin que nous puissions les utiliser.
Réponses:
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:
x
et que le type dérivé demandex
, que obtient-il?x
variables ont des types incongruents, vous pouvez en déduire.f
avec des signatures identiques, et que quelqu'un appellef
, qui appelle?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).
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é.
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é.
la source
with
mot clé fait ici.