2009-04-12 16 views

risposta

43

Il riferimento alla risposta di Jim, che era eccellente BTW, descriveva solo quando e dove utilizzare le direttive. Un'altra parte della risposta è perché sono necessari comunque? Molte lingue vanno d'accordo senza di loro, giusto? Durante la progettazione di aspetti del linguaggio Pascal Object Delphi, OOP (Object Oriented Programming) era stato nel mainstream per diversi anni. Durante questo periodo è stato osservato che l'utilizzo di molti dei linguaggi che avevano adottato questi concetti (Turbo Pascal, C++, ecc.) Per sviluppare framework applicativi soffriva di quello che chiamavo il problema della "versione 2".

Supponi di aver sviluppato un fantastico framework utilizzando il linguaggio X e di averlo rilasciato come versione 1. I tuoi utenti hanno deluso tutto ciò che potrebbe fare ed è diventato pesantemente utilizzato. Sfiora con successo, decidi di rilasciare la versione 2 con ancora più suggestione. In particolare, hai fatto in modo che fosse completamente compatibile con le versioni precedenti. All'improvviso, gli utenti hanno iniziato a segnalare comportamenti strani. I loro metodi virtuali venivano chiamati a volte strani. Molti hanno riferito che il loro vecchio codice non sarebbe stato compilato con la nuova versione. Strano. Rimangono tutti gli stessi oggetti, metodi e funzionalità. Tutto ciò che hai fatto è stato aggiungere alcuni metodi virtuali ad alcune classi base, alcuni nuovi tipi di oggetti e alcune nuove funzionalità opzionali. Quello che è successo?

L'override e reintrodurre le direttive servono per eliminare questo problema richiedendo che per realtà di override un metodo virtuale è necessario utilizzare per la direttiva di sostituzione al posto della direttiva virtuale. Se ti capita di introdurre il tuo metodo virtuale che ha lo stesso nome di uno dei metodi virtuali dei tuoi antenati, il compilatore ora ti avviserà, ma farà comunque la cosa giusta. In questo caso, usando reintroduce, non solo sopprime tale avviso, ma serve anche a documentare nella fonte che intendevi fare.

Senza l'override e reintrodurre le direttive, non si sarebbe in grado di evolvere continuamente il framework senza la paura di violare tutti gli utenti. E se i tuoi utenti dovessero apportare enormi modifiche ogni volta che viene rilasciata una nuova versione, allora sarebbe dispiaciuta adottare la nuova versione. Infine, l'uso di "override" consente anche al designer del framework di modificare il tipo di virtual negli antenati senza infrangere il codice utente. Ad esempio, in Delphi molti metodi sono contrassegnati come "dinamici" che è una forma di ricerca del metodo runtime basata su tabelle di polimorfismo. Non è performante come un normale virtual, quindi è solitamente usato per metodi che sono raramente sovrascritti e/o sono risposte alle azioni dell'utente in cui il sovraccarico extra non viene mai notato. Supponiamo che nella V1 del framework un metodo sia stato contrassegnato come "dinamico", ma in pratica ha finito per essere sovrascritto e chiamato più di quanto volevi. In V2, puoi cambiarlo in "virtuale" senza timore che il codice dell'utente venga violato.

La lingua Object Pascal di Delphi non è l'unico linguaggio per riconoscere questo problema. C# richiede l'uso di una direttiva "override" per lo stesso identico motivo. Il comitato per gli standard C++ sta finalmente riconoscendo il problema e sta modificando il linguaggio per supportarlo ... una specie di. In C++, se il nome e l'elenco dei parametri di un metodo corrispondono a quelli di un antenato virtuale, allora è un override (anche se non si dice "virtuale" sul discendente!).Per il nuovo standard C++, se si specifica "virtuale" e le firme non corrispondono, si tratta di un nuovo metodo virtuale introdotto sulla classe corrente. Se esiste una corrispondenza di firma con l'antenato e lo scrittore non ha l' intenzione di eseguire l'override, quindi la "nuova" parola chiave viene utilizzata per indicare al compilatore che questo è un nuovo virtuale per questa classe.

+0

FWIW, Wirth aveva anche una parola chiave 'override' nel suo Object Pascal/per Apple (per Mac), molto probabilmente per lo stesso motivo. E MS QuickPascal ce l'ha anche lui. Ma nessuno dei due ha avuto una "reintroduzione". –

+0

Spiegazione chiara e concisa: 10/10 –

8

La direttiva override viene utilizzata per sovrascrivere i metodi virtuali nelle classi ereditate.

La direttiva reintroduce viene utilizzata per dichiarare un metodo con lo stesso nome della classe superiore, ma con parametri diversi.

+4

reintroduce è necessario solo se il metodo (con gli stessi parametri) nella super classe è virtuale. Se non è virtuale non c'è bisogno di "reintrodurre" perché il metodo della classe super sarà nascosto comunque. –

6

E quando non dovrei usare la parola chiave ereditata in metodi sovrascritti?

Fondamentalmente, la risposta è quando non si desidera eseguire il metodo ereditato. Fai attenzione però, poiché non consentire l'esecuzione di un metodo ereditato, può interrompere la funzionalità di un oggetto ereditato in modo indesiderato, quindi assicurati di non introdurre effetti collaterali indesiderati.

Ad esempio, immagina di voler sovrascrivere completamente una funzione ereditata chiamata ApplicaDiscount, ma qualcuno ha codificato la percentuale di sconto nella classe di antenato. Se chiami l'ApplyDiscount ereditato, questo sostituirà il tuo codice o calcolerà un valore che verrà sovrascritto; in questo caso potresti semplicemente non chiamare ereditato e applicare lo sconto tu stesso.

(Questo è un esempio inventato così se qualcuno può pensare ad uno migliore si prega di aggiungerlo.)

1

Ci sono molte circostanze in cui non si desidera chiamare ereditato in un metodo sovrascritto.

In alcune librerie che utilizzo, il metodo di base genera un errore (ENotImplimented o simile). Ovviamente in tal caso non si desidera chiamare ereditato o il proprio codice genererebbe anche l'errore.

Alcune delle mie classi dispongono di un'implementazione predefinita che funziona nella maggior parte dei casi. Il metodo è solo sovrascritto per sostituire il valore predefinito e non è necessario chiamare il valore predefinito.

Ad esempio, la funzione GST (= imposta sulle vendite) sull'oggetto finanziario di base restituisce il 12,5% dell'importo ExGst e IncGst restituisce ExGst + GST.

Su oggetti di compensazione del reddito, GST restituisce sempre 0, quindi non è necessario chiamare la funzione ereditata.