关于继承C#

msi*_*yer 5 c# inheritance

我试图了解继承如何在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();
    }
}
Run Code Online (Sandbox Code Playgroud)

Main()的CIL(通用中间语言)代码如下所示:

.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
Run Code Online (Sandbox Code Playgroud)

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()
Run Code Online (Sandbox Code Playgroud)

castclass动物键入代码执行dog.OverRideMe(); .这被翻译为CIL as

IL_0016:callvirt实例void ConsoleApplication1.Animal :: OverRideMe()

我把动物对象扔到了Dog类型.为什么要dog.OverRideMe(); 在CIL中被翻译成上述声明?上面代码的输出是:

在此输入图像描述

此输出与Base类Animal无关,但CIL仍会调用它.

jas*_*son 4

您正在调用虚拟方法。虚拟方法的调用由对象的运行时类型决定。您可以随意称呼它Dog,但编译器仍然会发出指令来确定在运行时调用的适当方法。从的编译时类型开始,它沿着继承链向上移动,dog直到找到 的“顶级”定义1OverRideMe并为此发出一个虚拟方法调用。在这种情况下,定义的继承链中的最高位置OverRideMe位于Animal; 因此,它发出一个虚拟方法调用Animal.OverRideMe

这是之前的答案,可能会帮助您更好地理解正在发生的事情。

1:继承链中定义方法的最高位置。这里必须要小心,以了解方法隐藏如何以及什么不会影响这一点