質問

この質問にはすでに答えがあります:

vs をオーバーライドすることについて少し混乱しています。C# でメソッドを非表示にします。それぞれの実際の使用法と、その説明も歓迎します。 いつ それぞれを使用します。

オーバーライドについて混乱しています。なぜオーバーライドするのでしょうか?これまでに学んだことは、オーバーリングによって、シグネチャを変更せずに、派生クラスのメソッドに必要な実装を提供できるということです。

スーパークラスのメソッドをオーバーライドせずにサブクラスのメソッドを変更した場合、スーパークラスのメソッドも変更されますか?

また、次の点についても混乱しています。これは何を示していますか?

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?
}
役に立ちましたか?

解決

考慮する:

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

オーバーライドは、派生クラスが基本クラスよりも具体的な動作を持つことができる古典的な OO の方法です (一部の言語ではオーバーライドするしかありません)。オブジェクトに対して仮想メソッドが呼び出される場合、そのメソッドの最も派生したバージョンが呼び出されます。したがって、私たちが扱っているにもかかわらず、 isReallyDerived として BaseClass 次に、で定義されている機能 DerivedClass 使用されている。

隠すということは、まったく別の方法があることを意味します。電話するとき WriteNum() の上 isReallyDerived そうなると、別のものが存在するかどうかを知る方法はありません。 WriteNum() の上 DerivedClass だから呼ばれない。オブジェクトを処理する場合にのみ呼び出すことができます として ある DerivedClass.

ほとんどの場合、隠すことは悪いことです。一般に、派生クラスで変更される可能性がある場合はメソッドを仮想として指定し、派生クラスでオーバーライドする必要があります。ただし、次の 2 つの点で便利です。

  1. 上位互換性。もし DerivedClass 持っていた DoStuff() メソッド、そしてその後 BaseClass を追加するように変更されました。 DoStuff() (異なる人によって作成され、異なるアセンブリに存在する可能性があることに注意してください)、メンバーの非表示を禁止すると、突然、 DerivedClass 変更せずにバグっています。また、新しい場合は、 DoStuff() の上 BaseClass 仮想だったので、自動的にオンになります DerivedClass これをオーバーライドすると、呼び出すべきではないときに既存のメソッドが呼び出される可能性があります。したがって、非表示がデフォルトであることは良いことです (私たちは new 明確にするために、絶対に非表示にしたいのですが、それを省略すると非表示になり、コンパイル時に警告が表示されます)。

  2. 貧乏人の共分散。を考えてみましょう Clone() メソッドオン BaseClass 新しいものを返す BaseClass それは作成されたもののコピーです。上書きで DerivedClass これにより、 DerivedClass しかし、それを次のように返します BaseClass, 、あまり役に立ちません。私たちにできることは、仮想的に保護することです。 CreateClone() それはオーバーライドされます。で BaseClass 私たちは持っています Clone() これはこの結果を返します - そしてすべてがうまくいきます DerivedClass これを新しいもので隠します Clone() を返す DerivedClass. 。電話をかける Clone() の上 BaseClass 常に を返します BaseClass 参考資料となります。 BaseClass 値または DerivedClass 必要に応じて値を設定します。電話をかける Clone() の上 DerivedClass を返します DerivedClass 値、それがそのコンテキストで必要なものです。この原理には他にもバリエーションがありますが、それらはすべてかなりまれであることに注意してください。

2 番目のケースで注意すべき重要な点は、隠蔽を正確に使用していることです。 取り除く 使っている人としては、呼び出しコードに驚きました DerivedClass 合理的にそれを期待するかもしれない Clone() を返す DerivedClass. 。どの呼び出し方法でも結果は相互に一貫性を保たれます。ほとんどの場合、隠すことは意外な結果を招く危険があるため、一般に眉をひそめられます。これは、まさに隠蔽によって引き起こされることが多い問題そのものを解決するため、正当化されます。

全体として、隠すことは必要な場合もあり、役に立つことはほとんどありませんが、一般的には悪いことなので、十分に注意してください。

他のヒント

の上書きという方法がoverrideとして、基本クラスで定義されているときに、子孫クラスのメソッドの新しいvirtual実装を提供する場合である。

あなたは子孫クラスのメソッドの新しい実装を提供する場合、あなたの新しい実装がvirtualが指定されていない場合、

非表示は、その方法は、overrideとして基底クラスで定義された、またはされていないされている場合。

非表示は非常に頻繁に悪いです。あなたがすべてでそれを避けることができれば、あなたは一般的にそれをしない試してみてください。あなたが定義された実際の型の変数に呼び出されたときに非表示の方法は、唯一の基本クラス参照を使用していない場合は、使用されているので、非表示には、発生する予期しない事を引き起こす可能性があります...一方、上書きされている仮想メソッドは、で終わるだろう適切な方法のバージョンは、子クラスのベースクラス参照を使用して呼び出された場合でも、呼び出されます。

たとえば、これらのクラスを考えてみます:

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

レッツ・コール、それはマッチングのリファレンスで、InheritedClassのインスタンスで、これを好むます:

InheritedClass inherited = new InheritedClass();
inherited.Method1();
inherited.Method2();
あなたが期待すべきか

この返します。両方の方法は、彼らがInheritedClassのバージョンを実行していると言います。

  

InheritedClassメソッド1
を実行します   実行InheritedClass方法2

このコードは同じ、InheritedClassのインスタンスを作成するが、BaseClassの基準に格納する

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

通常は、OOPの原則の下で、あなたは上記の例と同じ出力を期待するべきです。しかし、あなたは同じ出力を得ることはありません。

  

InheritedClassメソッド1
を実行します   実行BaseClassの方法2

あなたはInheritedClassコードを書いた場合は、

、あなたはそれで書いたコードを実行するMethod2()へのすべての呼び出しを望んでいる可能性があります。通常、これはそれがどのように動作するかだろう - あなたが上書きされていることvirtual方法で作業していると仮定します。あなたはnew /隠された方法を使用しているので、しかし、それは代わりに、使用している参照のバージョンを呼び出します。

<時間>

もしあなたがの本当にその後、の必要な動作です。あなたはそこに行きます。しかし、私は強くそれはあなたが望むなら、コードを持つ大規模な建築問題があるかもしれないことを示唆しています。

メソッドのオーバーライド派生クラスで基本クラスのメソッドのデフォルト実装simpleyオーバーライドである。

メソッドの非表示:あなたは、派生クラスで仮想メソッドの前に「新しい」キーワードを利用することができます。

タグなど
class Foo  
{  
  public virtual void foo1()  
  {  

  }  
}  

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

  }  
}  
あなたがバーから派生している別のクラスBAR1を作る場合は、

今、あなたがバーでdefindあるfoo1のを上書きすることができます。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top