2009-07-07 7 views
10

Per essere chiari, non sto chiedendo se/perché l'ereditarietà multipla è buona o cattiva. Ho sentito molti argomenti da entrambe le parti di quel dibattito.Quando l'ereditarietà multipla può essere l'unica soluzione ragionevole?

Mi chiedo se esiste un qualsiasi tipo di problema di progettazione o scenario in C++ in cui l'ereditarietà multipla è l'unico modo per realizzare qualcosa, o almeno è il modo migliore per tutte le altre alternative al punto che non avrebbe senso prendere in considerazione qualsiasi altra cosa.

Ovviamente, questa domanda non si applica alle lingue che non supportano l'ereditarietà multipla.

+0

Una domanda simile: http://stackoverflow.com/questions/573913/a-use-for-multiple-inheritance –

risposta

10

Non è possibile eseguire policy-based design senza ereditarietà multipla. Pertanto, se la progettazione basata su criteri è il modo più elegante per risolvere il problema, significa che è necessario disporre di ereditarietà multipla per risolvere il problema, rispetto a tutte le altre opzioni.

L'ereditarietà multipla può essere molto utile se non viene utilizzata in modo improprio (come tutto, in qualsiasi lingua).

+2

Sarebbe questo implica che la progettazione basata su policy semplicemente non è possibile in una lingua come Java, o ci sono modi per aggirarlo? –

+0

In realtà, l'articolo collegato indica che l'ereditarietà multipla è solo il modello di implementazione più comune (con alcuni vantaggi significativi), non che è assolutamente necessario. – GalacticCowboy

+0

@Jeff L: la classe 'Proxy' in Java può essere utilizzata come soluzione alternativa. – finnw

5

C'è una situazione in cui si eredita da una classe e magari si implementano una o due interfacce in Java. Questo è qualcosa che risolverai con l'ereditarietà multipla in C++ penso.

2

Avevo letto su Interfacce Java e così via, per avere un'idea migliore della risposta a questa domanda. L'idea alla base di un'interfaccia è creare una classe astratta che funge da modello per un'altra classe. il vantaggio, qui, è che i modelli possono essere combinati all'interno di una classe concreta. Per esempio-Parent

Foodstore classe- Subclass- CoffeeShop Subclass- Bakery

Con questo albero di ereditarietà, un Foodstore può essere un forno o un CoffeeShop ma non entrambi. Ma allora come chiameremmo uno Starbucks?

Modo migliore, IMO-

Parent

Aula Foodstore Interface- CoffeeShop Interface- Bakery

public class Starbucks estende Foodstore implementa CoffeeShop, Panificio {...}

Avrete Devo sapere un po 'di Java per capirlo, ma ci sono. Le interfacce sono abbastanza elementari, IMO.

Come ulteriore riflessione, forse le interfacce sono progettate per obbedire "Non ripeterti". Ovvio, ora che lo dico.

3

ereditarietà multipla è utile se avete bisogno di ereditare comportamento, non solo contratto. Tuttavia, come dimostrano altre lingue, l'ereditarietà multipla non è l'unico modo per risolvere questo problema, a scapito di rendere più profondo il tuo albero ereditario. Di conseguenza, gli scenari in cui è necessario e possono utilizzare solo l'ereditarietà multipla.

0

Come è già stato detto sulle altre risposte:

  • utilizzando le classi di base virtuali puri come "Interfacce", come in Java (http://en.wikipedia.org/wiki/Interface_(Java)), questo è un O.Ö. molto comune modello in tutto O.O.lingue, non solo Java

  • Per fanno di polizia a base di progettazione

Ma anche:

  • Per comporre una classe con diversi mixins (http://en.wikipedia.org/wiki/Mixin); Considero questo un ottimo uso dell'eredità multipla per ottenere il riutilizzo del codice!
3

flussi C++ utilizzano l'ereditarietà multipla: istream e ostream sono entrambi i genitori di iostream. Dal momento che entrambi ereditano da ios_base, hai un diamante.

È l'unica soluzione "ragionevole" nel senso che sarebbe irragionevole per la parte in streaming delle librerie standard prendere la stessa linea degli algoritmi e delle raccolte. Quindi ostream si comporta polimorficamente piuttosto che essere un'interfaccia "tipizzata" come Iterator (*).

Non appena si dispone di polimorfismo dinamico, è necessario più ereditarietà per implementare più di un'interfaccia allo stesso tempo.

(*) Presumibilmente questo è perché qualsiasi altra cosa sarebbe un macello. Devi essere in grado di scrivere le funzioni reali che manipolano i flussi, piuttosto che costringere gli utenti ad avere modelli ovunque. Questo perché è comune scrivere su "alcuni stream, non so cosa fino al runtime", ma non voler manipolare "qualche raccolta, non so cosa fino al runtime".

1

Quando si desidera ereditare funzionalità anziché ruolo, caso nel punto boost::noncopyable (altri linguaggi che supportano questo (diversamente da Java e C#) chiamano questo mixin).

0

Quando è necessario combinare due o più gerarchie di classi di terze parti, ciascuna delle quali richiede che gli oggetti siano derivati ​​dalla classe base della stessa gerarchia, quindi la mancanza di ereditarietà multipla renderà il codice complesso e complesso.

namespace Object_Database { 
    class Object { 
     public: 
     virtual void store() ; 
     virtual void fetch() ; 
    }; 
} 

namespace Reflectives { 
    class Object { 
     public: 
     virtual std::vector<std::string> > membernames(); 
     virtual std::vector<std::string> > methodnames(); 
    }; 
} 

La prima gerarchia consente agli utenti di creare oggetti che possono essere serializzato da e verso un database ad oggetti, e richiede che tutti questi oggetti essere derivate dalla classe Object_Database :: oggetto. La seconda gerarchia consente agli utenti di creare oggetti che possono essere interrogati in fase di runtime per i nomi dei loro membri e richiede che tutti questi oggetti vengano derivati ​​da Reflectives :: Object.

Se avete bisogno di oggetti che possono fare entrambe le cose, basta scrivere:

class ReflectivePickle : 
    public Object_Database::Object, 
    public Reflectives::Object { 
    // ... 
    }; 

Le altre soluzioni sono irragionevoli.

0

Tendo ad usare l'ereditarietà multipla in C++ quando le classi base sono "classi di interfaccia", cioè classi base in cui tutti i metodi sono puramente virtuali, nessuno ha implementazioni [ricorda che puoi ancora definire un'implementazione, ma devi invocarla esplicitamente] e non ci sono membri di dati. Molto simile a "interfacce" in Java o (da quello che sento) C#.

Per utilizzare il polimorfismo in C++, non è possibile utilizzare la composizione, è necessario utilizzare l'ereditarietà (pubblica).

Quindi se la classe Bar eredita (pubblicamente) da stampabile e serializzabile, posso trattare l'oggetto come un oggetto stampabile, un oggetto serializzabile o un oggetto Bar (usando puntatori o riferimenti).

Con la composizione, non è possibile farlo.

0

Se vuoi vedere una bella implementazione di Multiple Eredità, controlla Eiffel. Risolvono il problema di diamanti attraverso funzionalità di ridenominazione, molto più semplice rispetto alla risoluzione portata e supporta anche l'eredità ripetuta diretta in modo tale che:

A ereditare B, B, B

in caso di necessità di utilizzare questo tipo di eredità.

La loro libreria del kernel è open source e l'ereditarietà multipla è ampiamente utilizzata se si desidera visualizzare esempi.

http://sourceforge.net/projects/eiffelstudio/files/

Problemi correlati