Domanda

A questa domanda ha già una risposta qui:

Io sono un po ' confuso sull'override vsnascondere un metodo in C#.Usi pratici di ogni sarebbe anche apprezzato, così come una spiegazione per quando si potrebbe usare ogni.

Mi sono confuso sull'override - perché abbiamo l'override?Quello che ho imparato finora è che da overring siamo in grado di fornire desiderato implementazione di un metodo di una classe derivata, senza modificare la firma.

Se io non l'override del metodo della superclasse, e ho apportare modifiche al metodo nel sub classe, che apportano modifiche alla super metodo di classe ?

Mi sono anche confuso circa i seguenti - questo cosa vuol dimostrare?

class A
{
    virtual m1()
    {
        console.writeline("Bye to all");
    }
}

class B : A
{
    override m1()
    {
        console.writeLine("Hi to all");
    }
}

class C
{
    A a = new A();
    B b = new B();
    a = b; (what is this)
    a.m1(); // what this will print and why?

    b = a; // what happens here?
}
È stato utile?

Soluzione

Prendere in considerazione:

public class BaseClass
{
  public void WriteNum()
  {
    Console.WriteLine(12);
  }
  public virtual void WriteStr()
  {
    Console.WriteLine("abc");
  }
}

public class DerivedClass : BaseClass
{
  public new void WriteNum()
  {
    Console.WriteLine(42);
  }
  public override void WriteStr()
  {
    Console.WriteLine("xyz");
  }
}
/* ... */
BaseClass isReallyBase = new BaseClass();
BaseClass isReallyDerived = new DerivedClass();
DerivedClass isClearlyDerived = new DerivedClass();

isReallyBase.WriteNum(); // writes 12
isReallyBase.WriteStr(); // writes abc
isReallyDerived.WriteNum(); // writes 12
isReallyDerived.WriteStr(); // writes xyz
isClearlyDerived.WriteNum(); // writes 42
isClearlyDerived.writeStr(); // writes xyz

L'override è il classico OO modo in cui una classe derivata può avere più di un comportamento specifico di una classe base (in alcune lingue non hai scelta, ma per farlo).Quando un virtuale viene chiamato il metodo su un oggetto, quindi la maggior parte dei derivati versione del metodo è chiamato.Quindi, anche se abbiamo a che fare con isReallyDerived come BaseClass quindi funzionalità definite in DerivedClass è utilizzato.

Nascondere significa che abbiamo un metodo completamente diverso.Quando si chiama WriteNum() su isReallyDerived quindi non c'è modo di sapere che c'è un diverso WriteNum() su DerivedClass quindi non è chiamato.Può essere chiamato solo quando abbiamo a che fare con l'oggetto come un DerivedClass.

La maggior parte del tempo nascosto è male.In genere, o si dovrebbe avere un metodo virtuale se la sua probabilità di essere cambiato in una classe derivata, e l'override nella classe derivata.Ci sono però due cose che è utile per:

  1. Compatibilità in avanti.Se DerivedClass aveva un DoStuff() il metodo, e poi in seguito BaseClass è stato modificato per aggiungere un DoStuff() metodo, (ricorda che possono essere scritti da persone diverse e sono presenti in diverse assemblee) quindi un divieto membro nascondere avrebbe improvvisamente DerivedClass buggy senza cambiare.Inoltre, se la nuova DoStuff() su BaseClass era virtuale, quindi automaticamente quello a DerivedClass un override, potrebbe portare al pre-esistenti metodo chiamato quando non dovrebbe.Quindi, è bene che nasconde il valore predefinito è la usiamo new per chiarire, noi sicuramente vogliamo nascondere, ma lasciando fuori nasconde ed emette un avviso di compilazione).

  2. Povero uomo di covarianza.Si consideri un Clone() metodo BaseClass restituisce una nuova BaseClass che è una copia di quella creata.In sostituzione di DerivedClass questo creerà un DerivedClass ma tornare come un BaseClass, che non è così utile.Quello che possiamo fare è avere un virtuale protetto CreateClone() che viene sottoposto a override.In BaseClass abbiamo un Clone() che restituisce il risultato di questo - e tutto va bene - in DerivedClass ci si nasconde con un nuovo Clone() che restituisce un DerivedClass.Chiamata Clone() su BaseClass restituirà sempre un BaseClass di riferimento, che sarà un BaseClass valore o un DerivedClass valore appropriato.Chiamata Clone() su DerivedClass restituirà un DerivedClass valore, che è quello che noi vogliamo in questo contesto.Ci sono altre varianti di questo principio, tuttavia, dovrebbe essere notato che sono tutti abbastanza raro.

Una cosa importante da notare il secondo caso, è che abbiamo utilizzato proprio per nascondere rimuovere sorprese al codice chiamante, come la persona che lo utilizza DerivedClass si può ragionevolmente aspettare che le sue Clone() per restituire un DerivedClass.I risultati di uno qualsiasi dei modi in cui potrebbe essere chiamato vengono mantenute costanti con gli altri.La maggior parte dei casi di nascondere il rischio di introduzione di sorprese, che è il motivo per cui essi sono generalmente visto di buon occhio.Questo è giustificato proprio perché si risolve il problema che nasconde introduce spesso.

In tutto, nascondendo a volte è necessario, raramente utile, ma generalmente male, in modo da essere molto attenti di esso.

Altri suggerimenti

principale è quando si fornisce una nuova implementazione override di un metodo in una classe discendente quando quel metodo è definito nella classe base come virtual.

Nascondere è quando si fornisce una nuova implementazione di un metodo in una classe discendente quando quel metodo è non definito nella classe base come virtual, o quando la nuova implementazione non specifica override.

Nascondere è molto spesso male; si dovrebbe in generale cercare di non farlo se si può evitare a tutti. Nascondere può causare cose inaspettate accadere, perché i metodi nascosti vengono utilizzati solo quando viene chiamato su una variabile del tipo effettivo definito, non se si utilizza un riferimento di classe di base ... d'altra parte, i metodi virtuali che sono forzate finirà con la versione metodo corretto di essere chiamato, anche quando viene chiamato utilizzando il riferimento della classe base in una classe figlia.

Per esempio, prendere in considerazione queste classi:

public class BaseClass
{
  public virtual void Method1()  //Virtual method
  {
    Console.WriteLine("Running BaseClass Method1");
  }
  public void Method2()  //Not a virtual method
  {
    Console.WriteLine("Running BaseClass Method2");
  }
}
public class InheritedClass : BaseClass
{
  public override void Method1()  //Overriding the base virtual method.
  {
    Console.WriteLine("Running InheritedClass Method1");
  }
  public new void Method2()  //Can't override the base method; must 'new' it.
  {
    Console.WriteLine("Running InheritedClass Method2");
  }
}

Let chiamata in questo modo, con un'istanza di InheritedClass, in un riferimento di corrispondenza:

InheritedClass inherited = new InheritedClass();
inherited.Method1();
inherited.Method2();

Questo restituisce quello che si dovrebbe aspettare; entrambi i metodi dicono che sono in esecuzione le versioni InheritedClass.

  

Esecuzione InheritedClass Method1
  Esecuzione InheritedClass Method2

Questo codice crea un'istanza della stessa, InheritedClass, ma memorizza in un riferimento BaseClass:

BaseClass baseRef = new InheritedClass();
baseRef.Method1();
baseRef.Method2();

In genere, secondo i principi OOP, si deve aspettare lo stesso output dell'esempio precedente. Ma non si ottiene lo stesso risultato:

  

Esecuzione InheritedClass Method1
  Esecuzione BaseClass Method2

Quando hai scritto il codice InheritedClass, si potrebbe aver voluto tutte le chiamate al Method2() per eseguire il codice che hai scritto in esso. Normalmente, questo sarebbe come funziona - supponendo che si sta lavorando con un metodo virtual che avete sovrascritto. Ma perché si sta utilizzando un metodo new / nascosto, chiama la versione sul riferimento che si sta utilizzando, invece.


Se questo è il comportamento che veramente vogliono , quindi; ci si va. Ma Vorrei suggerire che, se questo è ciò che si vuole, ci può essere un problema di architettura più grande con il codice.

L'Override dei metodi è semplicemente ignorare una implementazione di default di un metodo della classe base nella classe derivata.

Metodo Di Nascondersi :Si può fare uso della "nuova" parola chiave prima di un metodo virtuale in una classe derivata

come

class Foo  
{  
  public virtual void foo1()  
  {  

  }  
}  

class Bar:Foo  
{  
  public new virtual void foo1()  
  {   

  }  
}  

ora, se fai un'altra classe Bar1, che è derivata da Bar , è possibile eseguire l'override di pippo1 che è defind in Bar.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top