【问题标题】:Regarding Inheritance C#关于继承 C#
【发布时间】:2013-08-12 14:51:15
【问题描述】:

我试图了解继承在 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(通用中间语言)代码如下所示:

.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()

animalDog类型的castclass之后,代码执行dog.OverRideMe();。这被翻译成 CIL 为

IL_0016: callvirt 实例无效 ConsoleApplication1.Animal::OverRideMe()

我已将 animal 对象转换为 Dog 类型。为什么要将dog.OverRideMe();翻译成CIL中的上述语句?上面代码的输出是:

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

【问题讨论】:

  • 我不明白需要否决这个问题。至少留下评论,以便我改进它。
  • 你的问题很好,坦率地说是一个很好的问题。忽略仇恨者,这些天他们在网站上失控了 IMO。

标签: c# inheritance


【解决方案1】:

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

这里有一个previous answer,它可能会帮助您更好地了解正在发生的事情。

1:继承链中定义方法的最高位置。 这里必须注意了解方法隐藏的方式以及不影响此的方法。

【讨论】:

  • 您可能需要查看方法签名中的新关键字。这将调用实际类型的方法而不是覆盖。
  • @Sebi:有 no 关键字new 用于隐藏 OP 代码中的任何方法。
【解决方案2】:

上面写着“callvirt” - 虚拟表与“Animal”类相关联,因此应该放置调用。解析虚拟表后,在运行时,会调用预期的方法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-20
    • 1970-01-01
    • 2017-08-10
    • 1970-01-01
    • 2015-01-02
    • 1970-01-01
    相关资源
    最近更新 更多