1
class Program
{
    static void Main(string[] args)
    {
        B foo = new B();
        foo.DoWork();
        Console.ReadLine();
    }
}

public class A
{
    public virtual void DoWork() { Console.WriteLine("A"); }
}
public class B : A
{
    public override void DoWork() { base.DoWork();  Console.WriteLine("B"); }
}

StackOverflow例外が発生しないのはなぜですか?私が理解しているように、foo.DoWork()が呼び出され、次にbase.DoWork()が呼び出されます。これは仮想であり、クラスB.DoWork()メソッドでオーバーライドされ、スタックがオーバーフローするまでbase.DoWork()の呼び出しを繰り返します。 。このオーバーフローは、base(selfを呼び出す循環ループ)の代わりにこれを使用すると簡単に実現できます。この場合、仮想関数のオーバーライドを防ぐにはどうすればよいですか?

4

3 に答える 3

11

いいえ、使用baseしても仮想通話はできません。要点は、オーバーライドした場合でもbase実装を呼び出せるようにすることです。

生成された IL を見ると、使用されていないことがわかりますcallvirt

IL_0002:  call       instance void A::DoWork()

C#5仕様のセクション7.6.8から(強調鉱山):

base-access が仮想関数メンバー (メソッド、プロパティ、またはインデクサー) を参照する場合、実行時に呼び出す関数メンバーの決定 (§7.5.4) が変更されます。呼び出される関数メンバーは、B に関して関数メンバーの最も派生した実装 (§10.6.3) を見つけることによって決定されます (これの実行時型に関してではなく、非ベースアクセス)。したがって、仮想関数メンバーのオーバーライド内で、base-access を使用して関数メンバーの継承された実装を呼び出すことができます。base-access によって参照される関数メンバーが抽象である場合、バインド時エラーが発生します。

于 2013-01-24T22:08:22.637 に答える
2

A.DoWork仮想です。しかし、by という名前のメソッドbase.決して仮想ではありません。その構文は非仮想呼び出しを生成するため、最も派生したバージョンではなく、正確なメソッドが呼び出されます。

于 2013-01-24T22:08:27.920 に答える
1

仮想メソッドは、オーバーライド可能で、コードを含む単なるメソッドです。電話をかけるときは、電話base.DoWork()したいことを明示的に述べますA.DoWork()。その後、A.DoWork()呼び出されます。

抽象化してみてくださいA.DoWork()。コードを含めることはできません。base.DoWork()次に、 で実行するものが何もないため、コンパイル エラーが発生しbase.DoWork()ます。

于 2013-01-24T22:08:17.783 に答える