250

次の違いは何ですか?

ケース 1: 基本クラス

public void DoIt();

ケース 1: 継承されたクラス

public new void DoIt();

ケース 2: 基本クラス

public virtual void DoIt();

ケース 2: 継承されたクラス

public override void DoIt();

私が実行したテストに基づいて、ケース 1 と 2 はどちらも同じ効果があるようです。違いや好ましい方法はありますか?

4

14 に答える 14

323

オーバーライド修飾子は仮想メソッドで使用でき、抽象メソッドで使用する必要があります。これは、コンパイラがメソッドの最後に定義された実装を使用することを示します。基本クラスへの参照でメソッドが呼び出された場合でも、それをオーバーライドする実装が使用されます。

public class Base
{
    public virtual void DoIt()
    {
    }
}

public class Derived : Base
{
    public override void DoIt()
    {
    }
}

Base b = new Derived();
b.DoIt();                      // Calls Derived.DoIt

Derived.DoItをオーバーライドする場合に呼び出されますBase.DoIt

new 修飾子は、親クラスの実装ではなく、子クラスの実装を使用するようにコンパイラに指示します。クラスを参照していないが親クラスを参照しているコードは、親クラスの実装を使用します。

public class Base
{
    public virtual void DoIt()
    {
    }
}

public class Derived : Base
{
    public new void DoIt()
    {
    }
}

Base b = new Derived();
Derived d = new Derived();

b.DoIt();                      // Calls Base.DoIt
d.DoIt();                      // Calls Derived.DoIt

最初に を呼び出しBase.DoIt、次に を呼び出しますDerived.DoIt。これらは、基本メソッドをオーバーライドする派生メソッドではなく、たまたま同じ名前を持つ 2 つの完全に別個のメソッドです。

出典: Microsoft ブログ

于 2009-09-09T11:35:14.520 に答える
194

virtual : メソッドが継承者によってオーバーライドされる可能性があることを示します

override : 基本クラスの仮想メソッドの機能をオーバーライドし、さまざまな機能を提供します。

new :元のメソッド (仮想である必要はありません) を隠し、異なる機能を提供します。これは絶対に必要な場合にのみ使用してください。

メソッドを非表示にしても、基本クラスにアップ キャストすることで元のメソッドにアクセスできます。これはいくつかのシナリオで役立ちますが、危険です。

于 2009-09-09T11:36:10.387 に答える
21

最初のケースでは、親クラスの定義を隠しています。これは、オブジェクトを子クラスとして扱っている場合にのみ呼び出されることを意味します。クラスを親の型にキャストすると、親のメソッドが呼び出されます。2 番目のインスタンスでは、オブジェクトが子クラスまたは親クラスとしてキャストされているかどうかに関係なく、メソッドがオーバーライドされ、呼び出されます。

于 2009-09-09T11:35:04.693 に答える
11
  • newREFERENCE type(left-hand side of =) を尊重することを意味し、それによって参照型のメソッドを実行します。new再定義されたメソッドがキーワードを持たない場合は、そのまま動作します。また、非ポリモーフィック継承とも呼ばれます。つまり、「基本クラスの同じ名前のメソッドとはまったく関係のない、まったく新しいメソッドを派生クラスで作成しています。」- ウィテカー氏
  • override基本クラスでキーワードとともに使用する必要がある はvirtual、OBJECT 型 ( の右側=) を尊重することを意味し、参照型に関係なくオーバーライドされたメソッドを実行します。また、ポリモーフィック継承とも呼ばれます。

両方のキーワードが互いに反対であることを念頭に置く私の方法。

override:virtualメソッドをオーバーライドするには、キーワードを定義する必要があります。override参照型(基底クラス参照か派生クラス参照か)に関係なく、基底クラスでインスタンス化すると基底クラスのメソッドが実行されるキーワードを使用したメソッド。それ以外の場合は、派生クラスのメソッドが実行されます。

new: キーワードがメソッドで使用される場合、キーワードとは異なりoverride、参照型が重要です。派生クラスでインスタンス化され、参照型が基底クラスの場合、基底クラスのメソッドが実行されます。派生クラスでインスタンス化され、参照型が派生クラスの場合、派生クラスのメソッドが実行されます。つまり、overrideキーワードの対比です。さらに、新しいキーワードをメソッドに追加するのを忘れたり省略したりすると、コンパイラはデフォルトでnewキーワードが使用されているように動作します。

class A 
{
    public string Foo() 
    {
        return "A";
    }

    public virtual string Test()
    {
        return "base test";
    }
}

class B: A
{
    public new string Foo() 
    {
        return "B";
    }
}

class C: B 
{
    public string Foo() 
    {
        return "C";
    }

    public override string Test() {
        return "derived test";
    }
}

メインで呼び出す:

A AClass = new B();
Console.WriteLine(AClass.Foo());
B BClass = new B();
Console.WriteLine(BClass.Foo());
B BClassWithC = new C();
Console.WriteLine(BClassWithC.Foo());

Console.WriteLine(AClass.Test());
Console.WriteLine(BClassWithC.Test());

出力:

A
B
B
base test
derived test

新しいコード例、

1 つずつコメントを付けて、コードを操作します。

class X
{
    protected internal /*virtual*/ void Method()
    {
        WriteLine("X");
    }
}
class Y : X
{
    protected internal /*override*/ void Method()
    {
        base.Method();
        WriteLine("Y");
    }
}
class Z : Y
{
    protected internal /*override*/ void Method()
    {
        base.Method();
        WriteLine("Z");
    }
}

class Programxyz
{
    private static void Main(string[] args)
    {
        X v = new Z();
        //Y v = new Z();
        //Z v = new Z();
        v.Method();
}
于 2016-09-14T12:20:15.760 に答える
8

以下を試してください: (case1)

((BaseClass)(new InheritedClass())).DoIt()

編集: virtual+override は実行時に解決されます (つまり、override は仮想メソッドを実際にオーバーライドします)。一方、new は同じ名前の新しいメソッドを作成し、古いメソッドを非表示にします。コンパイル時に解決されます -> コンパイラはメソッドを呼び出します '見える」

于 2009-09-09T11:34:38.453 に答える
4

2 つのケースの違いは、ケース 1 では基本DoItメソッドがオーバーライドされず、単に隠されていることです。これが意味することは、変数の型に応じて、呼び出されるメソッドが異なるということです。例えば:

BaseClass instance1 = new SubClass();
instance1.DoIt(); // Calls base class DoIt method

SubClass instance2 = new SubClass();
instance2.DoIt(); // Calls sub class DoIt method

これは非常に混乱を招く可能性があり、予期しない動作が発生する可能性があるため、可能であれば回避する必要があります。したがって、推奨される方法はケース 2 です。

于 2009-09-09T11:38:03.017 に答える
4

ケース 1 では、型が基本クラスとして宣言されているときに継承されたクラスの DoIt() メソッドを呼び出すと、基本クラスのアクションも表示されます。

/* Results
Class1
Base1
Class2
Class2
*/
public abstract class Base1
{
    public void DoIt() { Console.WriteLine("Base1"); }
}
public  class Class1 : Base1 
{
    public new void DoIt() { Console.WriteLine("Class1"); }
}
public abstract class Base2
{
    public virtual void DoIt() { Console.WriteLine("Base2"); }
}
public class Class2 : Base2
{
    public override void DoIt() { Console.WriteLine("Class2"); }
}
static void Main(string[] args)
{
    var c1 = new Class1();
    c1.DoIt();
    ((Base1)c1).DoIt();

    var c2 = new Class2();
    c2.DoIt();
    ((Base2)c2).DoIt();
    Console.Read();
}
于 2009-09-09T11:41:39.717 に答える
3

私は同じ質問をしましたが、それは本当に紛らわしいです.overrideおよびnewキーワードは、タイプ基本クラスのオブジェクトと派生クラスの値でのみ機能することを考慮する必要があります。この場合のみ、override と new の効果が見られます: したがって、 と が から継承されている場合class ABBAようにオブジェクトをインスタンス化します。

A a = new B();

メソッドを呼び出すと、その状態が考慮されます。 Override : メソッドの機能を拡張し、派生クラスでメソッドを使用することを意味しますが、newは、派生クラスでメソッドを非表示にし、代わりに基本クラスでメソッドを使用するようにコンパイラに指示します。これはその主題の非常に良い光景です:

https://msdn.microsoft.com/EN-US/library/ms173153%28v=VS.140,d=hv.2%29.aspx?f=255&MSPPError=-2147217396

于 2016-04-14T09:03:21.803 に答える
1

キーワードoverrideが派生クラスで使用されている場合、親メソッドをオーバーライドします。

Keywordnewが派生クラスで使用されている場合、親メソッドによって隠されている派生メソッド。

于 2013-03-01T12:06:37.470 に答える