Esistono numerosi problemi con ereditarietà multipla quando vengono utilizzati con classi complete, ma ruotano tutti attorno all'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
x
variabili hanno tipi incongruenti, è possibile inferirle.
- Se sono dello stesso tipo, puoi provare a unirli nella stessa variabile.
- Puoi sempre esporli come nomi strani e completamente qualificati.
- Se hai due classi base con la stessa funzione
f
con firme identiche e qualcuno chiama f
, come viene chiamato?
- E se le due classi base condividessero un altro antenato virtuale comune (il problema del diamante).
- Cosa succede se la funzione ha firme diverse, ma compatibili?
- Quando costruisci una classe con due classi base, quale costruttore delle classi 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 gestite tutti questi casi con 3 classi base? 10?
E questo ignora cose come l'invio dinamico, l'inferenza del tipo, la corrispondenza dei modelli e altre cose che conosco di meno, che diventano più difficili quando il linguaggio supporta l'ereditarietà multipla di classi complete.
Tratti o Mix-in (o interfacce, o ...) sono tutti costrutti che limitano specificamente le capacità di un tipo in modo che non vi siano ambiguità. Raramente possiedono qualcosa da soli. Questo permette alla composizione dei tipi di diventare più fluida 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 adottato è quello di forzare l'utente a "costruire" (o mescolare) il proprio tipo uno alla volta. Invece che le classi di base siano partner uguali nel nuovo tipo, aggiungi un tipo a un altro - sovrascrivendo qualsiasi cosa fosse presente (di solito con sintassi opzionale per rinominare e / o ri-esporre i bit sovrascritti).
C'è qualcosa che non è possibile con mixin / tratti ma possibile con l'ereditarietà multipla in stile C ++?
A seconda della lingua, in genere diventa problematico o impossibile unire le implementazioni di funzioni e archiviazione per variabili da più classi di base ed esporle nel tipo derivato.
È possibile imbattersi in un problema al diamante con loro?
A volte variazioni meno gravi appariranno in base alla tua lingua, ma di solito no. L'intero punto dei tratti è quello di rompere quel tipo di ambiguità.