为什么虚拟方法被认为是早期约束?

时间:2010-03-10 18:51:30

标签: c#

绑定的一个定义是它是用内存地址替换函数名的行为。

a)因此我假设早期绑定意味着在编译过程中函数调用被替换为内存地址,而在后期绑定时,这种替换发生在运行时期间?

b)为什么虚方法也被认为是早期绑定(因此目标方法在编译时找到,并且创建了将调用此方法的代码)?据我所知,使用虚方法只能在运行时解析实际方法,而不是编译时间?!

感谢名单


编辑:

1)

A a=new A();
a.M();

据我所知,在编译时不知道在运行时是否在堆上创建实例a的堆(因此在哪个内存地址)。 现在,通过早期绑定,在编译过程中将函数调用替换为内存地址。但是编译器如何用内存地址替换函数调用,如果它不知道堆在运行时会在哪里创建对象a(这里我假设方法a.M的地址也将是在与a相同的内存位置?

2)

  

v-table调用既不早,也不晚。相反,函数指针表中存在偏移量。偏移量在编译时是固定的,但是从哪个表中选择函数指针取决于对象的运行时类型(该对象包含指向其v-table的隐藏指针),因此最终的函数地址在运行时找到。 / p>

但是假设类型T的对象是通过反射创建的(因此app甚至不知道类型T的存在),那么在编译时如何存在该类型的入口点对象?

3 个答案:

答案 0 :(得分:6)

晚期绑定

使用后期绑定,您拥有的只是方法的名称。在编译时,您无法知道该方法是否存在。这在Ruby或Python等语言中被称为“duck typing”。

后期绑定很慢,因为您必须按名称查找该功能。它也很危险,因为你没有受到轻微拼写错误的保护。

在版本4之前,除了显式调用反射API之外,C#不支持后期绑定。

早期绑定

使用早期绑定时,您将针对实际方法进行编译。该方法可以直接引用,也可以是V表中的槽。无论哪种方式,你都不会抛出MissingMethod异常。

<强>记录

Visual Basic以支持早期和晚期绑定而闻名,但由于它的其他限制,它从未被视为真正的动态语言。与此同时,7之前的版本(a.k.a. VB.NET)对强制执行早期绑定的支持非常差,因此很难将其称为静态语言。

使用.NET 4,可以说C#和VB都提供静态和动态类型语言所需的大多数功能。

有一次,Java被错误地说具有后期绑定支持,因为事实上它只有早期绑定,OOP风格的V-table。多年来,这引起了很多混乱。

答案 1 :(得分:1)

当编译器在编译时知道确切的类型时,虚拟方法是早期绑定的。

如果编译器没有确切的类型,它将生成vtable查找样式后期绑定。

答案 2 :(得分:1)

当Joshua解释时,对虚拟方法的调用可能是早期绑定的(即编译器可以看到对象的确切类型,没有进行多态),或者可以通过v-table进行调用。

当你使用反射时,C#只进行后期绑定(在下一个版本中,有一个新的“动态”关键字来请求后期绑定)。

v-table调用既不早,也不晚。相反,函数指针表中存在偏移量。偏移量在编译时是固定的,但是从哪个表中选择函数指针取决于对象的运行时类型(该对象包含指向其v-table的隐藏指针),因此最终的函数地址在运行时找到。 / p>

编辑以解决新问题:

在(1)中,整个前提是错误的。函数不会存储在“拥有”它们的对象附近的任何位置。实际上,整个程序只有一个函数副本,对象实例作为隐藏的“this”参数传递,因此函数知道正在处理哪个实例。

对于(2),有两种可能性。一,函数调用是通过MethodInfo等反射完成的。这真的是晚了。二,函数调用是通过调用者在编译时知道的接口或基类进行的,即使对象的总类型未知。在这种情况下,使用v表调用,因为v表的布局由基类或接口确定,因此调用者知道它并且可以预先确定到v表中的偏移量。