调用继承的方法

时间:2015-06-22 08:27:44

标签: c# oop inheritance

让我们假设我有一个父类和一个子类,我重载了一个父类方法。

我将子类对象分配给PARENT CLASS引用变量。我知道,当我尝试调用父类方法时,它将调用子类方法。

但是背后的原因是什么?什么是程序控制流程?堆里面发生了什么?

2 个答案:

答案 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成为可能:

  1. 特定类型的每个对象都有一个指向table的指针,该指针包含(指向)对 类型有效的虚拟方法实现。
  2. 继承不会改变表中方法的顺序(它可以在末尾添加更多方法),因此方法保留与在子类中覆盖它的索引相同的索引(并生成更多表)。
  3. 在运行时,编译器知道您正在调用的方法的索引,并使用该索引将该调用实现为表中的查找。

    • 由于上面的(1),无论对象在运行时碰巧具有哪种类型(与编译时声明的类型相反),都将使用包含正确方法实现的查找表。
    • 由于上面的(2),编译器使用的索引将“找到”正确的方法,即使在编译时运行时类型(因此查找表)是未知的。

    实际上,该机制适用于尚不存在的类型!可以在有人使子类型和方法实现特定于它之前很久就编写和编译方法调用。

    免责声明:C#实现的实际细节比上面描述的更复杂(例如,接口需要双重查找,有反射等),但基本思想保持不变。