web-dev-qa-db-ja.com

新規とオーバーライドの違い

次の違いは何なのか疑問に思います:

ケース1:基本クラス

public void DoIt();

ケース1:継承クラス

public new void DoIt();

ケース2:基本クラス

public virtual void DoIt();

ケース2:継承クラス

public override void DoIt();

ケース1と2の両方は、私が実行したテストに基づいて同じ効果があるように見えます。違いはありますか?

176
Shiraz Bhaiji

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

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を呼び出します。

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

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 blog

238
rahul

virtual:継承者がメソッドをオーバーライドできることを示します

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

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

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

167
Jon B

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

15
tvanfosson

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

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

編集:virtual + overrideは実行時に解決されます(したがって、オーバーライドは実際に仮想メソッドをオーバーライドします)見る

7
nothrow

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

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

メモとして、私は3年間C++に触れていませんが、私が説明する方法はまだあなたに役立つと信じています。


****新しいアイデアがここにあります! ****

以前の説明はまだ有効だと思いますが、コンセプトを統合して、心に留めておきたいと思います。 (インターンシップのため最近C#を使用しているため)

  • 経験則:newキーワードを「reference-side」にマッピングします。

どういう意味ですか?

X b                   =      new Y();
^^^^                         ^^^^^^^^
Reference side             Object side(= you)

参照型が重要であるため、newpatriarchalです。

あなたのreferenceは誰ですか、あなたは彼が誰なのかです。

newはRESPECT YOURREFERENCEを意味します!あなたはオブジェクト側です。 newを使用すると、重要ではなくなり、流行遅れになります。

using System;

namespace ConsoleApplication1
{
    class TestClass
    {
        public class BaseClass
        {
            public virtual void Foo()  { Console.WriteLine ("BaseClass.Foo"); }
        }

        public class Overrider : BaseClass
        {
            public override void Foo() { Console.WriteLine ("Overrider.Foo"); } 
        }

        public class Hider : BaseClass
        {
            public new void Foo() { Console.WriteLine ("Hider.Foo"); } 
        }


        public static void Main(string[] args)
        {
            Overrider over = new Overrider(); 
            BaseClass b1 = over;
            over.Foo();
            b1.Foo();

            Hider h = new Hider(); 
            BaseClass b2 = h; 
            h.Foo();
            b2.Foo();
        }
    }
}

詳細については、 C#7.0 in a nutshell:The Definitive Reference、by Joseph Albahari、Ben Albahari

3
snr

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です。

3
Shannon Cornish

ケース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();
}
3
Matthew Whited

これらのうち、newが最もわかりにくいです。実験を通じて、新しいキーワードは、開発者に、明示的に型を定​​義することにより、継承クラス実装を基本クラス実装でオーバーライドするオプションを提供するようなものです。それは逆に考えるようなものです。

次の例では、タイプがBaseClassテストとして明示的に定義されるまで、結果は「派生結果」を返します。その後、「ベース結果」が返されます。

class Program
{
    static void Main(string[] args)
    {
        var test = new DerivedClass();
        var result = test.DoSomething();
    }
}

class BaseClass
{
    public virtual string DoSomething()
    {
        return "Base result";
    }
}

class DerivedClass : BaseClass
{
    public new string DoSomething()
    {
        return "Derived result";
    }
}
1
usefulBee

以下の記事はvb.netにありますが、新しいvsオーバーライドに関する説明は非常に理解しやすいと思います。

https://www.codeproject.com/articles/17477/the-dark-shadow-of-overrides

記事のある時点で、次の文があります。

一般に、シャドウはそのタイプに関連付けられた関数が呼び出されると想定し、オーバーライドはオブジェクトの実装が実行されると想定します。

この質問に対する受け入れられた答えは完璧ですが、この記事はこれらの2つのキーワードの違いについてより良い意味を追加する良い例を提供すると思います。

1
Samuel

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

キーワードnewが派生クラスで使用される場合、派生メソッドは親メソッドによって非表示になります。

1
saba

最初のケースでは、新しいキーワードが基本クラスのDoIt()メソッドを隠すため、派生クラスのDoIt()メソッドを呼び出します。

2番目のケースでは、オーバーライドされたDoIt()を呼び出します

  public class A
{
    public virtual void DoIt()
    {
        Console.WriteLine("A::DoIt()");
    }
}

public class B : A
{
    new public void DoIt()
    {
        Console.WriteLine("B::DoIt()");
    }
}

public class C : A
{
    public override void DoIt()
    {
        Console.WriteLine("C::DoIt()");
    }
}

これらのクラスのインスタンスを作成しましょう

   A instanceA = new A();

    B instanceB = new B();
    C instanceC = new C();

    instanceA.DoIt(); //A::DoIt()
    instanceB.DoIt(); //B::DoIt()
    instanceC.DoIt(); //B::DoIt()

上記ですべてが期待されています。 instanceBとinstanceCをinstanceAに設定し、DoIt()メソッドを呼び出して結果を確認します。

    instanceA = instanceB;
    instanceA.DoIt(); //A::DoIt() calls DoIt method in class A

    instanceA = instanceC;
    instanceA.DoIt();//C::DoIt() calls DoIt method in class C because it was overriden in class C
0
cimey

機能の違いは、これらのテストでは表示されません。

BaseClass bc = new BaseClass();

bc.DoIt();

DerivedClass dc = new DerivedClass();

dc.ShowIt();

この例では、呼び出されるDoitは、呼び出されると予想されるDoitです。

違いを確認するには、これを行う必要があります。

BaseClass obj = new DerivedClass();

obj.DoIt();

そのテストを実行すると、ケース1(定義したとおり)でBaseClassDoIt()が呼び出され、ケース2(定義したとおり)でDerivedClassDoIt()が呼び出されますと呼ばれます。

0
Ken Falk

私は同じ質問を持っていて、本当に混乱しています。overridenewタイプがベースクラスのオブジェクトと派生クラスの値でのみ機能するキーワード。この場合にのみ、オーバーライドと新規の効果が表示されます。したがって、class AおよびBを持っている場合、BAから継承し、次のようなオブジェクトをインスタンス化します。この:

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

0
user4451265