Originariamente avevo chiesto a questa domanda su StackOverflow, ma ero diretto qui, e penso che il mio problema sia tanto concettuale quanto tecnico, quindi ecco qui.
Se stai definendo una gerarchia di classi astratte in C ++ e poi creando sottoclassi concrete con implementazioni, potresti finire con classi astratte come questa, per esempio:
A
/ \
B1 B2
Quindi le classi concrete quindi ereditano in questo modo:
B1 B2 B1 B2
| | | |
C1 C2 D1 D2
E questo è tutto fine e dandy quando Cn
e Dn
stanno solo implementando le interfacce di Bn
, o dove dicono C1
e C2
implementano l'interfaccia A
in modo diverso .
Tuttavia, se voglio avere una funzionalità condivisa in C1
e C2
, che proviene dall'interfaccia A
, dove la metto?
Non può andare in A
, sia perché A
è astratto e perché Dn
dovrebbe non ereditarlo.
Sembra che esista un'implementazione di A_for_C
teorico, ma questo appartiene a un'altra classe di antenati? O in una classe fratello composta?
_____A_____ _____A_____
/ | \ / | \
B1 A_for_C B2 vs B1 B2 A_for_C
|_____/ \____ | | |
C1 C2 C1 C2
(C1 and C2 then each have an A_for_C and delegate)
Il primo sembra concettualmente accurato, ma richiede ereditarietà virtual
, mentre il secondo richiede delega. Quindi entrambi impongono un successo in termini di prestazioni nonostante non ci sia alcuna reale ambiguità.
Leggendo sul web, su questo sito lo trovo detto
Some people believe that the purpose of inheritance is code reuse. In C++, this is wrong. Stated plainly, “inheritance is not for code reuse.”
In che modo quindi l'implementazione dovrebbe essere condivisa?
Ulteriori pensieri
Ho trovato alcune discussioni pertinenti in queste domande:
- dove proviene questo concetto di "favorire la composizione sull'eredità"?
- Interfaccia ed ereditarietà: il meglio di entrambi i mondi?
- Esiste "reale "la ragione dell'ereditarietà multipla è odiata?
Penso che la risposta di utnapistim sotto sia molto più concisa e al punto di questi, e mi ha aiutato a tagliare mentalmente molte delle domande e delle risposte di queste altre domande.
La successione riguarda l'accettazione di un contratto. L'ereditarietà multipla va bene se la sottoclasse garantisce realmente l'adempimento dei contratti parent.
L'implementazione, tuttavia, è solo la vera preoccupazione dell'oggetto finale. Sì, potrebbe essere conveniente ereditare l'implementazione a volte, ma in realtà è ortogonale all'interfaccia e ci sono varie tecniche per implementare un'implementazione diversa dall'approccio basato su v-table predefinito, tra cui:
- CRTP come da risposta di unaptism
- Il modello di metodo del modello
(Che sono, penso, equivalente tranne che uno è in fase di compilazione e uno è in fase di esecuzione.)