2013-06-01 4 views
7

Le persone dicono che l'ereditarietà del C++ è malvagia, quindi Java ha risolto questo problema con l'interfaccia.Il mixaggio di Scala è davvero migliore di più ereditarietà in C++?

Ma Scala ha introdotto trait s, sono ... interfaccia con implementazione parziale? Questo non ha portato indietro più eredità?

Significa che i ragazzi di Scala pensano che l'eredità multipla sia buona? Oppure hanno alcune differenze critiche che non ho notato?

+6

Per favore, date un'occhiata al libro [Programming in Scala] (http://www.artima.com/pins1ed/traits.html#12.6), pagina 258, §12.6. Ho trovato questa spiegazione estremamente valida e potrei provare a riformularla, ma non lo farei - è difficile scrivere qualcosa di più completo di così. In breve, in Scala non esiste il cosiddetto [* diamond problem *] (https://en.wikipedia.org/wiki/Multiple_inheritance#The_diamond_problem) (che esiste in C++ ed è per questo che l'eredità multipla di C++ è stata criticata così male) , a causa della mancanza di costruttori, ordine di invocazione del metodo ben definito e nozione differente di * super *. –

risposta

8

La parte peggiore dell'eredità multipla è l'ereditarietà del diamante, in cui una sottoclasse ha due o più percorsi verso lo stesso genitore da qualche parte lungo la catena. Questo crea ambiguità se le implementazioni differiscono lungo i due percorsi (cioè sono sovrascritte dall'implementazione originale). In C++ la soluzione è particolarmente brutta: si incorporano entrambe le classi parent incompatibili e si deve specificare quando si chiama quale implementazione si desidera. Ciò crea confusione, crea lavoro extra in ogni sito di chiamata (o, più probabilmente, ti costringe a sovrascrivere esplicitamente e indica quello che desideri, questo lavoro manuale è tedioso e introduce una possibilità di errore) e può portare a oggetti più grandi di dovrebbero essere.

Scala risolve alcuni ma non tutti i problemi limitando l'ereditarietà multipla ai tratti. Poiché i tratti non hanno costruttori, la classe finale può linearizzare l'albero di ereditarietà, vale a dire che anche se due genitori su un percorso di ritorno a un super-genitore comune nominalmente sono entrambi genitori, uno è quello "corretto", vale a dire quello elencato per ultimo. Questo schema lascerebbe intere classi half-initialized spezzate se potessi avere costruttori (completamente generici), ma così com'è, non devi incorporare la classe due volte, e al sito use puoi ignorare quanta ereditarietà se ne ha è accaduto. Tuttavia, non è molto più facile ragionare su ciò che accadrà quando si sovrappongono molti tratti l'uno sull'altro, e se erediti sia da B sia da C, non è possibile scegliere di prendere di di B le implementazioni e alcune delle C.

Quindi è meglio in quanto affronta alcune delle critiche più gravi del modello C++. Se sia meglio è una questione di gusti; molte persone amano anche il gusto dell'eredità multipla del C++ abbastanza bene da usarlo.

+0

Preferisco specificare esplicitamente i membri ambigui piuttosto che fare affidamento su una regola che fa scelte non ovvie. – nclark

+0

@joeytwiddle - Ho appena notato che hai colto il mio errore più di un anno e mezzo fa! Risolto il problema –

+0

@nclark - Non otterrai le scelte non ovvie a meno che tu non stia già scavalcando, quindi c'è una certa protezione contro scelte non ovvie. Ma una volta che hai già sovraccaricato in entrambi i rami, sì, l'ultimo elencato viene scelto automaticamente, e si potrebbe sostenere che anche l'esplicito sarebbe migliore. (Se solo per specificare quale implementazione della superclasse si desidera.) –

Problemi correlati