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的循环循环)时,很容易实现这种溢出。在这种情况下,什么阻止虚函数覆盖?
答案 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()
无法执行任何操作。