5

C# で継承がどのように機能するかを理解しようとしています。次のコードを書きました。

class Program
{
    static void Main(string[] args)
    {
        Animal animal = new Dog();
        animal.OverRideMe();
        //animal.NewMethod();
        Dog dog = (Dog)animal;
        dog.OverRideMe();
        dog.NewMethod();
        Console.Read();
    }
}
public abstract class Animal
{
    public Animal()
    {
        Console.WriteLine("Base Constructor");
    }
    public virtual void OverRideMe()
    {
        Console.WriteLine("In Base Class's OverRideMe");
        Console.Read();
    }
}
public class Dog : Animal
{
    public Dog()
    {
        Console.WriteLine("Derived Constructor");
    }
    public override void OverRideMe()
    {
        Console.WriteLine("In Derived Class's OverRideMe");
        Console.Read();
    }
    public void NewMethod()
    {
        Console.WriteLine("In Derived Class's NewMethod");
        Console.Read();
    }
}

Main() の CIL (Common Intermediate Language) コードは次のようになります。

.method private hidebysig static 
    void Main (
        string[] args
    ) cil managed 
{
    // Method begins at RVA 0x2050
    // Code size 42 (0x2a)
    .maxstack 1
    .entrypoint
    .locals init (
        [0] class ConsoleApplication1.Animal animal,
        [1] class ConsoleApplication1.Dog dog
    )

    IL_0000: nop
    IL_0001: newobj instance void ConsoleApplication1.Dog::.ctor()
    IL_0006: stloc.0
    IL_0007: ldloc.0
    IL_0008: callvirt instance void ConsoleApplication1.Animal::OverRideMe()
    IL_000d: nop
    IL_000e: ldloc.0
    IL_000f: castclass ConsoleApplication1.Dog
    IL_0014: stloc.1
    IL_0015: ldloc.1
    IL_0016: callvirt instance void ConsoleApplication1.Animal::OverRideMe()
    IL_001b: nop
    IL_001c: ldloc.1
    IL_001d: callvirt instance void ConsoleApplication1.Dog::NewMethod()
    IL_0022: nop
    IL_0023: call int32 [mscorlib]System.Console::Read()
    IL_0028: pop
    IL_0029: ret
} // end of method Program::Main

私を悩ませているCILの行は次のとおりです。

IL_000f: castclass ConsoleApplication1.Dog
IL_0014: stloc.1
IL_0015: ldloc.1
IL_0016: callvirt instance void ConsoleApplication1.Animal::OverRideMe()
IL_001b: nop
IL_001c: ldloc.1
IL_001d: callvirt instance void ConsoleApplication1.Dog::NewMethod()

animalからDogタイプへのcastclassの後、コードはdog.OverRideMe();を実行します。. これは CIL に次のように変換されます。

IL_0016: callvirt インスタンス void ConsoleApplication1.Animal::OverRideMe()

動物オブジェクトを型にキャストしました。なぜdog.OverRideMe();が必要なのですか?CILの上記のステートメントに翻訳されますか? 上記のコードの出力は次のとおりです。

ここに画像の説明を入力

この出力は Base クラスのAnimalとは関係ありませんが、CIL は依然としてそれを呼び出します。

4

2 に答える 2

4

仮想メソッドを呼び出しています。仮想メソッドの呼び出しは、オブジェクトのランタイムタイプによって決まります。必要なだけ呼び出すことができますが、コンパイラは実行時Dogに呼び出す適切なメソッドを決定する命令を発行します。のコンパイル時の型から始めて、の「トップレベル」定義1が見つかるまで継承チェーンをたどり、その仮想メソッド呼び出しを発行します。この場合、定義されている継承チェーンの最上位は inです。したがって、 の仮想メソッド呼び出しを発行します。dogOverRideMeOverRideMeAnimalAnimal.OverRideMe

これは、何が起こっているのかをもう少しよく理解するのに役立つかもしれない以前の回答です。

1 : メソッドが定義されている継承チェーンの最上位。メソッドの隠蔽とこれに影響を与えない方法を理解するには、ここで注意が必要です。

于 2013-08-12T14:57:35.207 に答える
0

「callvirt」と表示されます。仮想テーブルは「Animal」クラスに関連付けられているため、そこに呼び出しを行う必要があります。仮想テーブルを解決した後、実行時に目的のメソッドが呼び出されます。

于 2013-08-12T14:58:09.197 に答える