In che modo i mixin o i tratti sono migliori di una semplice ereditarietà multipla?

51

C ++ ha una ereditarietà multipla, molti design di linguaggio lo proibiscono come pericoloso. Ma alcune lingue come Ruby e PHP usano strane sintassi per fare la stessa cosa e chiamarla mixin o tratti. Ho sentito molte volte che mixin / tratti sono più difficili da abusare di una semplice ereditarietà multipla.

Cosa li rende in particolare meno pericolosi? C'è qualcosa che non è possibile con mixin / tratti ma possibile con l'ereditarietà multipla in stile C ++? È possibile imbattersi nel problema del diamante con loro?

Sembra che stessimo usando l'ereditarietà multipla ma solo scusandoci che quelli sono mixin / tratti in modo che possiamo usarli.

    
posta Gherman 22.07.2014 - 22:32
fonte

1 risposta

31

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:

  1. 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.
  2. 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?
  3. Quando costruisci una classe con due classi base, quale costruttore della classe base viene chiamato per primo? Quando distruggi l'oggetto, che viene ucciso?
  4. Quando disponi l'oggetto in memoria, come lo fai in modo coerente?
  5. 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à.

    
risposta data 22.07.2014 - 23:15
fonte