C#でのメソッドのオーバーライドと非表示について少し混乱しています。 when oneがそれぞれを使用するのと同様に、それぞれの実用的な使用も評価されます。
オーバーライドについて混乱しています-なぜオーバーライドするのですか?これまでに学んだことは、オーバーライドすることで、署名を変更せずに、派生クラスのメソッドに望ましい実装を提供できることです。
スーパークラスのメソッドをオーバーライドせずにサブクラスのメソッドを変更した場合、スーパークラスのメソッドも変更されますか?
また、以下についても混乱しています-これは何を実証していますか?
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
で定義された機能が使用されます。
非表示とは、まったく異なる方法があることを意味します。 isReallyDerived
でWriteNum()
を呼び出すと、DerivedClass
で別のWriteNum()
があることを知る方法がないため、呼び出されません。オブジェクトを処理しているときにのみ呼び出すことができますas a DerivedClass
。
ほとんどの場合、隠れることは悪いことです。一般的に、派生クラスで変更される可能性がある場合は、メソッドを仮想として使用し、派生クラスでオーバーライドする必要があります。ただし、次の2つの点が役立ちます。
前方互換性。 DerivedClass
にDoStuff()
メソッドがあり、その後BaseClass
がDoStuff()
メソッドを追加するように変更された場合(それらは異なる人々と異なるアセンブリに存在する)、メンバーの非表示の禁止は、それを変更せずに突然DerivedClass
バギーにしたでしょう。また、BaseClass
の新しいDoStuff()
が仮想の場合、DerivedClass
でそれを自動的にオーバーライドすると、既存のメソッドが必要なときに呼び出される可能性があります't。したがって、非表示がデフォルトであることは良いことです(new
を使用して、明確に非表示にすることを明確にしますが、非表示のままにすると、コンパイル時に警告が表示されます)。
貧者の共分散。作成されたもののコピーである新しいBaseClass
を返すBaseClass
のClone()
メソッドを考えてください。 DerivedClass
のオーバーライドでは、これはDerivedClass
を作成しますが、それをBaseClass
として返しますが、これはあまり有用ではありません。できることは、オーバーライドされた仮想保護されたCreateClone()
を持つことです。 BaseClass
には、この結果を返すClone()
があり、すべてが順調です-DerivedClass
には、これを新しいClone()
で非表示にしますDerivedClass
を返します。 BaseClass
でClone()
を呼び出すと、常にBaseClass
参照が返されます。これは、必要に応じてBaseClass
値またはDerivedClass
値になります。 DerivedClass
でClone()
を呼び出すと、DerivedClass
値が返されます。これは、そのコンテキストで必要なものです。この原則には他にも変形がありますが、それらはすべて非常にまれであることに注意する必要があります。
2番目のケースで注意すべき重要なことは、DerivedClass
を使用している人がClone()
はDerivedClass
を返します。呼び出される可能性のある方法の結果は、互いに一貫性が保たれます。サプライズをもたらすリスクを隠すほとんどのケースは、一般的に眉をひそめている理由です。これは、隠蔽がしばしばもたらす問題をまさに解決するため、正確に正当化されます。
全体的に、非表示は時々必要であり、あまり有用ではありませんが、一般的には非表示なので、非常に注意してください。
オーバーライドは、そのメソッドがoverride
として基本クラスで定義されているときに、下位クラスのメソッドの新しいvirtual
実装を提供する場合です。
非表示は、そのメソッドがnotが基本クラスでvirtual
として定義されている場合、または新しい実装がoverride
。
非表示は非常に頻繁に悪いです。回避できる場合は、一般的にしないでください。 Hiddenメソッドは、基本クラス参照を使用している場合ではなく、定義した実際の型の変数で呼び出された場合にのみ使用されるため、非表示が予期せぬ事態を引き起こす可能性があります...子クラスの基本クラス参照を使用して呼び出された場合でも、適切なメソッドバージョンが呼び出されます。
たとえば、次のクラスを検討してください。
_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 Method1の実行
InheritedClass Method2の実行
このコードは、同じInheritedClassのインスタンスを作成しますが、BaseClass参照に保存します。
_BaseClass baseRef = new InheritedClass();
baseRef.Method1();
baseRef.Method2();
_
通常、OOP原則では、上記の例と同じ出力を期待する必要がありますが、同じ出力は得られません。
InheritedClass Method1の実行
BaseClass Method2の実行
InheritedClassコードを記述したとき、Method2()
へのすべての呼び出しで、コードに記述したコードを実行したい場合があります。通常、これはどのように機能するか-オーバーライドしたvirtual
メソッドで作業していると仮定します。ただし、new
/hiddenメソッドを使用しているため、代わりに使用している参照のバージョンを呼び出します。
それがあなたの振る舞いだとしたらtruly want、そこに行きます。しかし、もしそれがあなたが望むものであれば、コードに大きなアーキテクチャ上の問題があるかもしれないことを強くお勧めします。
メソッドのオーバーライドは、派生クラスの基本クラスメソッドの既定の実装を簡単にオーバーライドします。
メソッドの非表示:派生クラスの仮想メソッドの前に「新しい」キーワードを使用できます
として
class Foo
{
public virtual void foo1()
{
}
}
class Bar:Foo
{
public new virtual void foo1()
{
}
}
ここで、Barから派生した別のクラスBar1を作成すると、Barで定義されているfoo1をオーバーライドできます。