0

我一直在阅读有关virtual方法的文档:

在虚拟方法调用中,发生该调用的实例的运行时类型决定了要调用的实际方法实现。在非虚拟方法调用中,实例的编译时类型是决定因素。准确地说,当在编译时类型为 C 和运行时类型为 R(其中 R 是 C 或从 C 派生的类)的实例上使用参数列表 A 调用名为 N 的方法时,调用是处理如下...: http: //msdn.microsoft.com/en-us/library/aa645767 (v=vs.71).aspx

但是,我注意到上面加粗的东西。假设我们有这样的代码:

class Planet{
  public string Name;
  public float Size;
  public virtual void SpinPlanet(){
     Console.WriteLine("Hoooraaay!!!");
  }
}

class Earth : Planet{

}

在我的代码中某处我做:

Earth world = new Earth();
world.SpinPlanet();

在这种情况下:

  • NSpinPlanet()
  • CEarth
  • RPlanet

那么怎么会R派生出编译时类型的类呢C。基类类型不是在运行时解析的吗?

4

2 回答 2

3

你错了——编译时类型(C)是Earth 运行时类型(R)也是 Earth。您指出的规范部分在这里并不真正相关。

相关的是http://msdn.microsoft.com/en-us/library/aa691356(v=vs.71).aspx,具体来说:

构造方法调用的候选方法集。从与 M 相关联的一组方法开始,这些方法是通过先前的成员查找(第 7.3 节)找到的,该组被简化为适用于参数列表 A 的那些方法。

just的唯一候选实现SpinPlanet恰好在 的基类中Earth,而不是派生类中。

如果代码是,您引用的规范部分将适用:

Planet world = new Earth();
world.SpinPlanet();

(特别是如果 Earth 为 定义了覆盖SpinPlanet),因为编译类型(变量的类型)将是Planet,但运行时类型将是Earth.

于 2012-04-18T17:55:04.770 回答
2

调用的正确方法将在运行时通过从Virtual Methods Table中选择来解决。所以如果你添加到Earth

class Earth : Planet{
   public override void SpinPlanet(){
     Console.WriteLine("Hoooraaay Earth!!!");
  }
}

在这样的代码上

Planet world = new Earth();
world.SpinPlanet(); //even if declared type Planet, 
                    // the real type remain Earth, so its  method will be called

将被调用Earth's方法。

我的示例中,编译时类型是Planet,但运行时类型是Earth.

您的示例中,编译时和运行时类型是相同的Earth

于 2012-04-18T17:52:38.327 回答