Question

    

Cette question a déjà une réponse ici:

         

Je suis un peu confus sur le remplacement par rapport à cacher une méthode en C #. utilisations pratiques de chacun seraient également appréciés, ainsi qu'une explication pour lorsque on utiliserait chacun.

Je suis confus au sujet primordial - pourquoi nous remplaçons? Ce que j'ai appris est jusqu'à présent que par overring nous pouvons fournir la mise en oeuvre désirée à une méthode d'une classe dérivée, sans changer la signature.

Si je ne l'emporte pas sur la méthode de la superclasse et je fais des changements à la méthode de la sous-classe, cela fera des changements à la méthode super classe?

Je suis aussi confus au sujet de ce qui suit - qu'est-ce que cela démontre

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?
}
Était-ce utile?

La solution

Considérez:

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

Redéfinition est la voie OO classique dans lequel une classe dérivée peut avoir un comportement plus spécifique qu'une classe de base (dans certaines langues que vous avez pas d'autre choix que de le faire). Quand une méthode virtuelle est appelée sur un objet, la version la plus dérivée de la méthode est appelée. Par conséquent, même si nous avons affaire à isReallyDerived comme BaseClass alors la fonctionnalité définie dans DerivedClass est utilisé.

moyens de Masquage que nous avons une méthode complètement différente. Lorsque nous appelons WriteNum() sur isReallyDerived alors il n'y a aucun moyen de savoir qu'il ya un autre WriteNum() sur DerivedClass il est donc pas appelé. Il ne peut être appelée lorsque nous avons affaire à l'objet comme DerivedClass.

La plupart du temps caché est mauvais. En règle générale, que ce soit, vous devriez avoir une méthode aussi virtuelle si elle susceptible d'être modifiée dans une classe dérivée, et le remplacer dans la classe dérivée. Il y a cependant deux choses, il est utile pour:

  1. Compatibilité avant. Si DerivedClass avait une méthode de DoStuff(), puis plus tard BaseClass a été modifié pour ajouter une méthode de DoStuff(), (rappelez-vous qu'ils peuvent être écrits par des personnes différentes et existent dans différentes assemblées), puis une interdiction de cacher membre aurait soudainement fait buggy DerivedClass sans elle en changeant. En outre, si le nouveau DoStuff() sur BaseClass était virtuelle, puis faire automatiquement sur DerivedClass un remplacement de celui-ci pourrait conduire à la méthode pré-existante appelée quand il ne devrait pas. Par conséquent, il est bon que la clandestinité est la valeur par défaut (nous utilisons new pour le rendre clair que nous voulons absolument cacher, mais en laissant des peaux et émet un avertissement sur la compilation).

  2. covariance Poor man. Considérons une méthode Clone() sur BaseClass qui retourne une nouvelle BaseClass qui est une copie de celui créé. Dans la dérogation sur DerivedClass cela va créer un DerivedClass mais revenir comme BaseClass, ce qui est aussi utile. Ce que nous pourrions faire est d'avoir un CreateClone() virtuel protégé qui est surchargée. En BaseClass nous avons un Clone() qui renvoie le résultat de ce - et tout va bien - en DerivedClass nous cacher cela avec une nouvelle Clone() qui retourne une DerivedClass. Appel Clone() sur BaseClass renvoie toujours une référence BaseClass, qui sera une valeur BaseClass ou une valeur de DerivedClass selon le cas. Appel Clone() sur DerivedClass retournera une valeur DerivedClass, qui est ce que nous voudrions dans ce contexte. Il existe d'autres variantes de ce principe, mais il convient de noter qu'ils sont assez rares.

Une chose importante à noter le second cas, est que nous avons utilisé précisément pour cacher supprimer des surprises au code appelant, comme la personne qui utilise DerivedClass peut légitimement attendre son Clone() retourner un DerivedClass . Les résultats de l'une des façons il pourrait être appelé sont maintenus cohérents entre eux. La plupart des cas de cacher des surprises présentant des risques, ce qui explique pourquoi ils sont généralement mal vus. Celui-ci se justifie précisément parce qu'elle permet de résoudre le problème même qui cache souvent présente.

En tout, caché est parfois nécessaire, souvent utile, mais généralement mauvais, alors soyez très prudent de celui-ci.

Autres conseils

est Redéfinition lorsque vous fournissez une nouvelle implémentation de override d'une méthode dans une classe descendante lorsque cette méthode est définie dans la classe de base comme virtual.

Hiding est lorsque vous fournissez une nouvelle mise en œuvre d'une méthode dans une classe descendante lorsque cette méthode est pas défini dans la classe de base comme virtual, ou lorsque votre nouvelle implémentation ne précise pas override.

Hiding est très souvent mauvaise; vous devriez essayer généralement de ne pas le faire si vous pouvez l'éviter à tout. Masquage peut provoquer des choses inattendues se produire, parce que les méthodes cachées ne sont utilisés que lorsqu'ils sont appelés à une variable du type réel que vous avez défini, pas si vous utilisez une référence de classe de base ... d'autre part, les méthodes virtuelles qui sont ignorées finiront par la bonne version méthode appelée, même lorsqu'il est appelé en utilisant la référence de classe de base sur une classe enfant.

Par exemple, considérons ces classes:

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");
  }
}

L'appel Let comme ça, avec une instance de InheritedClass, dans une référence correspondant:

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

Ce rendement ce que vous devez attendre; les deux méthodes disent qu'ils sont en cours d'exécution les versions InheritedClass.

  

Running InheritedClass Method1
  Exécution InheritedClass Method2

Ce code crée une instance du même, InheritedClass, mais stocke dans une référence BaseClass:

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

Normalement, en vertu des principes de la POO, vous devriez vous attendre le même résultat que l'exemple ci-dessus. Mais vous ne recevez pas la même sortie:

  

Running InheritedClass Method1
  Exécution BaseClass Method2

Lorsque vous avez écrit le code InheritedClass, vous avez sans doute voulu tous les appels à Method2() pour exécuter le code que vous avez écrit en elle. Normalement, ce serait comment cela fonctionne - en supposant que vous travaillez avec une méthode de virtual que vous avez remplacé. Mais parce que vous utilisez une méthode new / caché, il appelle la version sur la référence que vous utilisez, à la place.


Si tel est le comportement que vous voulez vraiment , puis; Voilà. Mais je suggère fortement que si c'est ce que vous voulez, il peut y avoir un plus grand problème d'architecture avec le code.

méthode redéfinie est prioritaire simpley une implémentation par défaut d'une méthode de la classe de base dans la classe dérivée.

Méthode Hiding: Vous pouvez utiliser mot-clé « nouveau » avant une méthode virtuelle dans une classe dérivée

class Foo  
{  
  public virtual void foo1()  
  {  

  }  
}  

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

  }  
}  

si vous faites une autre classe Bar1 qui est dérivé de Bar, vous pouvez remplacer foo1 qui est defind dans la barre.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top