Perché i metodi virtuali devono essere sovrascritti in modo esplicito in C#?WHY i metodi virtuali devono essere esplicitamente ignorati in C#?
risposta
Dichiarando un metodo come virtual
, sei indicando la tua intenzione che il metodo può essere ignorato in una classe derivata.
Dichiarando il tuo metodo di esecuzione in quanto override
, il vostro sono indicando la vostra intenzione questo modo si sostituisce un metodo virtual
.
Richiedendo l'utilizzo della parola chiave override
per sovrascrivere un metodo virtuale, i progettisti del linguaggio incoraggiano la chiarezza, richiedendo di indicare le proprie intenzioni.
Perché rende il codice più leggibile:
class Derived : Base
{
void Foo();
}
In C++, Foo può o non può essere un metodo virtuale, non possiamo dire guardando la definizione. In C# sappiamo che un metodo è virtuale (o non lo è) perché c'è una parola chiave virtuale o override.
Il commento di Jason di seguito è una risposta migliore.
(a cura per chiarezza)
... e offre ad Intellisense la possibilità di aiutarci a scavalcare un metodo. Digita "override" e Intellisense si apre con una scelta e riempie persino l'intera firma del metodo per noi. Quanto è fantastico? – Tergiver
... e, cosa più importante, permette al compilatore di dirci quando commettiamo un errore (ad esempio se aggiungi un parametro al metodo della classe base in C++, interrompe tutte le classi derivate ma non hai modo di conoscerlo - una causa di alcuni bug davvero maliziosi, perché i bit del comportamento della classe derivata smettono di funzionare in silenzio. In C# restituisce un errore per ogni override che non sovrascrive più nulla) –
_ "In C++ potrebbe essere, possiamo ' t dire guardando la definizione. "_ - Osservando la definizione, possiamo dire che non è affatto C++. – stakx
Se non si aggiunge la parola chiave override
, il metodo verrà nascosto (come se fosse la parola chiave new
), non sovrascritto.
Ad esempio:
class Base {
public virtual void T() { Console.WriteLine("Base"); }
}
class Derived : Base {
public void T() { Console.WriteLine("Derived"); }
}
Base d = new Derived();
d.T();
Questo codice stampe Base
. Se si aggiunge override
all'implementazione Derived
, il codice verrà stampato Derived
.
Non è possibile farlo in C++ con un metodo virtuale. (There is no way to hide a C++ virtual method without overriding it)
Non tutti i metodi virtuali devono essere sovrascritti, sebbene tutti i metodi astratti debbano (e debbano) essere. Per quanto riguarda il motivo per cui la parola chiave 'override' è esplicita, perché override e hiding si comportano diversamente. Un metodo di nascondimento non viene chiamato attraverso un riferimento a una classe base, mentre è un metodo sovrascritto. Questo è il motivo per cui il compilatore avverte in modo specifico su come dovresti usare la "nuova" parola chiave nel caso in cui ti stai nascondendo piuttosto che sovrascrivere.
È perché i membri del team C# sono tutti programmatori C++ qualificati. E sa come incipiente questo particolare bug è:
class Base {
protected:
virtual void Mumble(int arg) {}
};
class Derived : public Base {
protected:
// Override base class method
void Mumble(long arg) {}
};
è molto più comune, allora si potrebbe pensare. La classe derivata viene sempre dichiarata in un altro file di codice sorgente. Normalmente non si sbaglia subito, succede quando si refactoring. Nessun peep dal compilatore, il codice funziona abbastanza normalmente, semplicemente non fa quello che ti aspetti che faccia. Puoi guardarlo per un'ora o un giorno e non vedere il bug.
Questo non può mai accadere in un programma C#. Anche il C++ gestito ha adottato questa sintassi, rompendo intenzionalmente la sintassi C++ nativa. Sempre una scelta coraggiosa IntelliSense elimina la verbosità in più.
C'è un sacco di modifiche alla sintassi in C# che assomigliano a questo tipo di sintassi per evitare errori.
EDIT: e il resto della comunità di C++ ha accettato e ha adottato il di override parola chiave nella nuova specifica del linguaggio C++ 11.
+1 Risposta migliore IMO perché spiega il "perché" alla base della decisione sulla progettazione della lingua anziché "come funzionano le chiamate virtuali" in quanto le risposte con rating più elevato fanno ... PS. @Hans Sembra che tu stia sbattendo un sacco di risposte pertinenti da te scritte in questi giorni :) –
Non è necessario sovrascrivere esplicitamente un metodo virtuale in una classe derivata. Contrassegnare un metodo virtuale consente solo l'override.
- 1. I distruttori virtuali devono essere pubblici?
- 2. I metodi che implementano metodi virtuali puri di una classe di interfaccia devono essere dichiarati anche virtuali?
- 3. Perché i metodi parziali devono essere annullati?
- 4. Come funzionano i metodi virtuali in C#?
- 5. I metodi astratti sono virtuali?
- 6. Perché i metodi statici devono essere inclusi in una classe?
- 7. Mocking metodi non virtuali in C#
- 8. I temi sembrano essere ignorati in ICS
- 9. Java: tutti i metodi statici devono essere sincronizzati?
- 10. I flag enum C# devono essere sequenziali
- 11. java @SafeVarargs perché i metodi privati devono essere definitivi
- 12. I metodi Robot devono essere eseguiti sulla coda eventi?
- 13. metodi non-virtuali imperative
- 14. Tabelle dei metodi virtuali
- 15. Metodi statici C# virtuali (o astratti)
- 16. No RTTI ma metodi ancora virtuali
- 17. Quali file di Visual Studio devono essere ignorati da subversion per minimizzare i conflitti?
- 18. Metodi non virtuali in Java
- 19. C++: funzioni virtuali che devono chiamare lo stesso codice?
- 20. I comandi devono essere asincroni in CQRS?
- 21. I campi devono essere esplicitamente definitivi per avere un oggetto "corretto" immutabile?
- 22. In C#, perché le implementazioni di interfaccia devono implementare esplicitamente un'altra versione di un metodo?
- 23. Perché i tipi WinRT devono essere sigillati?
- 24. I parametri del modello devono essere tipi?
- 25. I metodi di asserzione JUnit devono essere espressi in positivo o in negativo?
- 26. Come simulare metodi non virtuali?
- 27. In Java, i metodi che non utilizzano variabili statiche o di classe devono essere sincronizzati?
- 28. Perché i metodi di test in Junit devono essere definiti pubblici?
- 29. metodi virtuali e classi template
- 30. Quanto devono essere diversi i semi casuali?
Perché non contrassegnarlo come 'astratto' e forzare l'override? –
@George: perché puoi usare il modificatore astratto solo nelle classi astratte. –
@George Stocker - Perché potresti non voler contrassegnare l'intera classe come astratta (la classe ha bisogno del modificatore astratto per avere metodi astratti). –