5

IL 提供了两种调用函数的语句,即 call 和 callvirt。Call 用于调用非虚拟或静态函数或编译器不想对引用进行空检查的任何函数。

callvirt 用于调用虚函数,也调用非虚函数,因为编译器在运行时对引用进行空检查。

现在在通过 C# 浏览 CLR 时,我发现了以下示例。

internal class SomeClass
{
   public override String ToString()
   {
      return base.ToString();
   }
}

现在 ToString() 是虚函数,但是编译器为其生成调用指令就可以了。但是 Jeffrey 提到为什么不生成 callvirt 的原因是因为在这种情况下 ToString() 将被递归调用并会导致 StackOverFlow 异常,我试图理解但无法理解这个想法?谁能解释为什么它会导致递归调用?

谢谢..

4

2 回答 2

2

据我所知,如果编译器生成 callvirt 会发生 stackoverflow 异常,因为:

一些代码调用从类object继承的someclass类型的对象的 ToString 。*somclass" 方法的 ToString 方法调用它的基类object的 ToString 方法。

如果此调用虚拟的,则不会导致从类对象调用 ToString ,而是调用实际类(即SomeClass)的 ToString 。

然后你就会进入一个不定式循环,因为整个事情将从现在开始。

于 2010-02-09T08:16:08.073 回答
2

对特定超类的显式调用(在这种情况下System.Object是因为您编写了base不能因为这会callvirt导致堆栈溢出。

一些 C# 伪代码:

internal class SomeClass
{
   public override String ToString()
   {
       // The "return base.ToString()" call could produce one of these two possibilities:

       // This will NOT go through the class hierarchy, searching for a overwritten function
       // called ToString
       call and return System.Object::ToString()

       // But this WILL, thus calling SomeClass::ToString() recursively, so this is wrong
       // and would lead to a stack overflow
       callvirt and return System.Object::ToString()
   }
}

希望这就是你的意思。

于 2010-02-09T08:19:23.260 回答