Esistono numerosi problemi con l'ereditarietà multipla quando vengono utilizzati con classi complete, ma ruotano tutti intorno a ambiguità .
L'ambiguità si presenta in diversi modi:
- Se hai due classi base con lo stesso campo
x
, e il tipo derivato chiede x
, che cosa ottiene?
- Se le due variabili
x
hanno tipi incongruenti, puoi dedurlo.
- Se sono dello stesso tipo, puoi provare a unirli nella stessa variabile.
- Potresti sempre esporli come nomi completamente qualificati.
- Se hai due classi base con la stessa funzione
f
con firme identiche e qualcuno chiama f
, che viene chiamato?
- Cosa succede se le due classi base condividono un altro antenato virtuale comune (il problema del diamante).
- Che cosa succede se la funzione ha firme diverse, ma compatibili?
- Quando costruisci una classe con due classi base, quale costruttore della classe base viene chiamato per primo? Quando distruggi l'oggetto, che viene ucciso?
- Quando disponi l'oggetto in memoria, come lo fai in modo coerente?
- Come gestisci tutti questi casi con 3 classi base? 10?
E questo ignora cose come invio dinamico, inferenza di tipo, corrispondenza dei pattern e altre cose di cui so meno su quali diventano più impegnative quando il linguaggio supporta l'ereditarietà multipla di classi complete.
Tratti o Mix-in (o interfacce, o ...) sono tutti costrutti che specificano limit le capacità di un tipo in modo che non ci sia ambiguità. Raramente possiedono qualcosa da soli. Questo permette alla composizione di tipi di andare più fluidi perché non ci sono due variabili o due funzioni ... c'è una variabile e un riferimento; una funzione e una firma. Il compilatore sa cosa fare.
L'altro approccio comune è quello di costringere l'utente a "costruire" (o mescolare) il loro tipo uno alla volta. Invece che le classi base sono partner uguali nel nuovo tipo, si aggiunge un tipo a un altro, ignorando tutto ciò che era presente (di solito con la sintassi opzionale per re-nominare e / o riesporre i bit sostituiti).
Is there something that isn't possible with mixins/traits but possible with C++-style multiple inheritance?
A seconda della lingua - generalmente diventa problematico o impossibile fondere implementazioni di funzioni e archiviazione per variabili da più classi di base ed esporle nel tipo derivato.
Is it possible to run into diamond problem with them?
Occasionalmente vengono visualizzate varianti meno gravi in base alla lingua, ma di solito no. L'intero punto dei tratti è quello di rompere questo tipo di ambiguità.