我想知道下面的代码是如何优化的。特别是关于虚拟和直接调用。我已经评论过我认为一切都已优化,但这些只是猜测。
public abstract class Super
{
public abstract void Foo();
public void FooUser()
{
Foo();
}
}
public class Child1 : Super
{
public override void Foo()
{
//doSomething
}
}
public class SealedChild : Super
{
public override void Foo()
{
//doSomething
}
}
class Program
{
void main()
{
Child1 child1 = new Child1();
child1.Foo(); //Virtual call?
child1.FooUser(); //Direct call and then a virtual call.
SealedChild sealedChild = new SealedChild();
sealedChild.Foo(); //Direct call?
sealedChild.FooUser();
/* Two options: either a direct call & then a virtual call
* Or: direct call with a parameter that has a function pointer to Foo, and then a direct call to foo.
*/
Super super = child1;
super.Foo(); //Virtual call.
super.FooUser(); //Virtual call then direct call.
}
}
如果密封类上有虚方法,并且对象引用的类型是密封类,则可以避免虚调用。以下面的例子为例。没有实际原因需要虚拟调用 GetName,因为我们知道不能有 Parent 的子类,因此没有进一步的虚拟分派(dispatch)。
sealed class Parent : Child {
public override string GetName() { return "foo"; }
}
public void Test() {
var p = new Parent();
var name = p.GetName();
}
编译器可以选择注意到这一点并输出调用 IL 指令而不是 callvirt。然而,C# 和 VB.Net 编译器都选择不执行此优化。两者都会发出 callvirt。
JIT也可以自由地做这样的优化。它也选择不这样做。
但这并不意味着您不应该密封您的类(class)。类应该是密封的,除非你真的打算让某人继承它们。否则,您将面临无法准确计算成本的情况。
此外,没有什么可以阻止编译器和 JIT 在以后实现它。
我是一名优秀的程序员,十分优秀!