2014-05-11 12 views

risposta

5

Se si eredita privatamente in C++, si ottiene l'ereditarietà senza sottotitoli. Cioè, dato:

class Derived : Base  // note the missing public before Base 

Non si può scrivere:

Base * p = new Derived(); // type error 

Perché Derived non è un sottotipo di Base. Hai semplicemente ereditato l'implementazione, non il tipo.

+2

Tecnicamente, è ancora ottenere sottotipizzazione con l'ereditarietà privata, è solo che il sottotipo è privato per la classe ... – Mankarse

+0

Se cambio l'eredità a: classe derivata: public Base mi può scrivere: Base * p = new derivato(); –

6

L'ereditarietà consiste nell'ottenere attributi (e/o funzionalità) di super-tipi. Ad esempio:

class Base { 
    //interface with included definitions 

} 

class Derived inherits Base { 
    //Add some additional functionality. 
    //Reuse Base without having to explicitly forward 
    //the functions in Base 
} 

Qui, un Derived non possono essere usati dove è previsto un Base, ma è in grado di agire in modo simile a un Base, mentre l'aggiunta di comportamento o cambiare qualche aspetto del comportamento Base s. In genere, Base sarebbe una piccola classe di supporto che fornisce sia un'interfaccia che un'implementazione per alcune funzionalità comunemente desiderate.

sottotipo-polimorfismo è sull'implementazione di un'interfaccia, e quindi essere in grado di sostituire diverse implementazioni di tale interfaccia in fase di esecuzione:

class Interface { 
    //some abstract interface, no definitions included 
} 

class Implementation implements Interface { 
    //provide all the operations 
    //required by the interface 
} 

Qui, una Implementation può essere utilizzato ovunque sia necessario un Interface, e diverse implementazioni possono essere sostituite in fase di esecuzione. Lo scopo è quello di consentire il codice che utilizza Interface per essere più ampiamente utile.

La tua confusione è giustificata. Java, C# e C++ si combinano tutte queste due idee in una singola gerarchia di classi. Tuttavia, i due concetti non sono identici e esistono linguaggi che separano i due.

+0

Puoi elencare le lingue che separano le due? – letronje

+0

@letronje: l'ereditarietà senza sottotipizzazione viene spesso implementata tramite un concetto [mixin] (https://en.wikipedia.org/wiki/Mixin) (ma un mixin è spesso leggermente meno limitato dell'ereditarietà). Ad esempio, in D, puoi scrivere [template mixins] (http://dlang.org/template-mixin.html), che sono essenzialmente un modo per iniettare codice e dati in un ambito arbitrario. – Mankarse

8

Un parente purtroppo è morto e ti ha lasciato la sua libreria.

Ora puoi leggere tutti i libri lì, venderli, puoi guardare i suoi conti, la sua lista clienti, ecc. Questa è l'eredità - hai tutto ciò che il parente aveva. L'ereditarietà è una forma di riutilizzo del codice.

È possibile anche ri-apre il negozio di libri da soli, assumendo tutti i ruoli e le responsabilità del parente, anche se si aggiungono alcune modifiche del proprio - questo è subtyping - ora sei un proprietario di una libreria, proprio come il tuo parente era solito essere.

Subtyping è un componente chiave di OOP: si dispone di un oggetto di un tipo ma che soddisfa l'interfaccia di un altro tipo, quindi può essere utilizzato ovunque sia possibile utilizzare l'altro oggetto.

Nelle lingue che hai elencato nella tua domanda - C++, Java e C# - i due sono (quasi) sempre usati insieme, e quindi l'unico modo per ereditare da qualcosa è sottotitolarlo e viceversa. Ma altri linguaggi non fondono necessariamente i due concetti.

16

Oltre alle risposte già fornite, ecco un link per un articolo che ritengo pertinente. Estratti:

Nel quadro orientato agli oggetti, l'ereditarietà è di solito presentata come una caratteristica che va di pari passo con il sottotipo quando si organizza tipi di dati astratti in una gerarchia di classi. Tuttavia, i due sono idee ortogonali.

  • Sottotipo si riferisce alla compatibilità delle interfacce. Un tipo B è un sottotipo di A se ogni funzione che può essere invocata su un oggetto di tipo A può anche essere invocata su un oggetto di tipo B.
  • L'ereditarietà si riferisce al riutilizzo delle implementazioni. Un tipo B eredita da un altro tipo A se alcune funzioni per B vengono scritte in termini di funzioni di A.

Tuttavia, la sottotipizzazione e l'ereditarietà non devono andare di pari passo. Considera la deque della struttura dei dati, una coda a doppio attacco. Una deque supporta l'inserimento e la cancellazione ad entrambe le estremità, quindi ha quattro funzioni insert-front, delete-front, insert-rear e delete-rear. Se usiamo solo insert-rear e delete-front otteniamo una coda normale. D'altra parte, se usiamo solo insert-front e delete-front, otteniamo uno stack. In altre parole, possiamo implementare code e stack in termini di deques, così come i tipi di dati, Stack e Queue ereditano da Deque. D'altra parte, né Stack non Queue sono sottotipi di Deque poiché non supportano tutte le funzioni fornite da Deque. Infatti, in questo caso, Deque è un sottotipo di entrambi Stack e Queue!

Penso che Java, C++, C# e il loro tipo abbiano contribuito alla confusione, come già notato, dal fatto che consolidano entrambe le idee in una singola gerarchia di classi. Tuttavia, penso che l'esempio sopra riportato renda giustizia alle idee in un modo agnostico piuttosto linguistico. Sono sicuro che altri possono dare più esempi.

+2

Quello era un estratto perfettamente selezionato. Grazie per la condivisione mi ha aiutato a chiarire i miei dubbi. – CapturedTree

Problemi correlati