为什么在覆盖和调用虚函数时我没有得到stackoverflow异常?

时间:2013-01-24 22:06:07

标签: c# override stack-overflow virtual-functions

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的循环循环)时,很容易实现这种溢出。在这种情况下,什么阻止虚函数覆盖?

3 个答案:

答案 0 :(得分: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引用的函数成员是抽象的,则会发生绑定时错误。

答案 1 :(得分:2)

A.DoWork是虚拟的。但是base.命名的方法永远不会虚拟。该语法生成​​非虚拟调用,因此调用确切的方法,而不是最派生的版本。

答案 2 :(得分:1)

虚方法只是一种可以覆盖并包含代码的方法。当您致电base.DoWork()时,您明确声明要拨打A.DoWork()。然后,调用A.DoWork()

尝试使A.DoWork()抽象,然后它不能包含代码。然后,您将在base.DoWork()上遇到编译错误,因为base.DoWork()无法执行任何操作。