让我们假设我有一个父类和一个子类,我重载了一个父类方法。
我将子类对象分配给PARENT CLASS引用变量。我知道,当我尝试调用父类方法时,它将调用子类方法。
但是背后的原因是什么?什么是程序控制流程?堆里面发生了什么?
答案 0 :(得分:5)
这里的“魔法”是查找表。
当您将方法声明为virtual时,该方法将添加到链接到该类型的表中,并且对该方法的所有调用都将查找要在表中调用的方法的地址。
因此,不是在对特定地址的特定方法的调用中编译,而是将调用编译为查找,然后调用从表中检索的值。
例如,假设基类型具有此表:
[1000]
对于第一种类型,有问题的方法是在地址1000处。
对于第二种类型,此表如下所示:
[2000]
同样(被覆盖的)方法现在在地址2000处。
如果方法不是虚拟的,则调用它,如此调用:
baseObject.Method1();
将被编译为类似的东西:
call method at address 1000
但现在它看起来像这样:
get address to type virtual method table (vtable)
get adress from index 0 in the table
call the method at that address
答案 1 :(得分:1)
有两个关键因素使dynamic dispatch成为可能:
在运行时,编译器知道您正在调用的方法的索引,并使用该索引将该调用实现为表中的查找。
实际上,该机制适用于尚不存在的类型!可以在有人使子类型和方法实现特定于它之前很久就编写和编译方法调用。
免责声明:C#实现的实际细节比上面描述的更复杂(例如,接口需要双重查找,有反射等),但基本思想保持不变。