オーバーライドとメソッドの非表示 [重複]
-
27-09-2019 - |
質問
この質問にはすでに答えがあります:
- C# におけるシャドウイングとオーバーライドの違いは? 5 つの答え
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 つの点で便利です。
上位互換性。もし
DerivedClass
持っていたDoStuff()
メソッド、そしてその後BaseClass
を追加するように変更されました。DoStuff()
(異なる人によって作成され、異なるアセンブリに存在する可能性があることに注意してください)、メンバーの非表示を禁止すると、突然、DerivedClass
変更せずにバグっています。また、新しい場合は、DoStuff()
の上BaseClass
仮想だったので、自動的にオンになりますDerivedClass
これをオーバーライドすると、呼び出すべきではないときに既存のメソッドが呼び出される可能性があります。したがって、非表示がデフォルトであることは良いことです (私たちはnew
明確にするために、絶対に非表示にしたいのですが、それを省略すると非表示になり、コンパイル時に警告が表示されます)。貧乏人の共分散。を考えてみましょう
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コードを書いた場合は、InheritedClassメソッド1
を実行します 実行BaseClassの方法2
、あなたはそれで書いたコードを実行するMethod2()
へのすべての呼び出しを望んでいる可能性があります。通常、これはそれがどのように動作するかだろう - あなたが上書きされていることvirtual
方法で作業していると仮定します。あなたはnew
/隠された方法を使用しているので、しかし、それは代わりに、使用している参照のバージョンを呼び出します。
もしあなたがの本当にその後、の必要な動作です。あなたはそこに行きます。しかし、私は強くそれはあなたが望むなら、コードを持つ大規模な建築問題があるかもしれないことを示唆しています。
メソッドのオーバーライド派生クラスで基本クラスのメソッドのデフォルト実装simpleyオーバーライドである。
メソッドの非表示:あなたは、派生クラスで仮想メソッドの前に「新しい」キーワードを利用することができます。
タグなど
class Foo
{
public virtual void foo1()
{
}
}
class Bar:Foo
{
public new virtual void foo1()
{
}
}
あなたがバーから派生している別のクラスBAR1を作る場合は、今、あなたがバーでdefindあるfoo1のを上書きすることができます。