C# 为什么虚拟方法被认为是早期绑定的?

C# 为什么虚拟方法被认为是早期绑定的?,c#,C#,绑定的一个定义是,它是用内存地址替换函数名的行为 a) 因此,我假设早期绑定意味着函数调用在编译过程中被替换为内存地址,而对于后期绑定,这种替换发生在运行时 b) 为什么虚拟方法也被认为是早期绑定的(因此目标方法是在编译时找到的,并且创建了调用此方法的代码)?据我所知,对于虚拟方法,对实际方法的调用只在运行时解决,而不是在编译时解决 塔克斯 编辑: (一) 据我所知,在编译时不知道在运行时在堆上的哪个位置(因此在哪个内存地址)将创建实例a。 现在,通过早期绑定,在编译过程中,函数调用将替换为内

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

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

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

塔克斯


编辑:

(一)

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

(二)

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


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

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


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

后期绑定

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

后期绑定很慢,因为必须按名称查找函数。这也很危险,因为你没有受到保护,不受轻微拼写错误的影响

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

早期绑定

使用早期绑定时,根据实际方法编译。此方法可以直接引用,也可以是V形表中的一个槽。无论哪种方式,您都被夸耀为不会抛出MissingMethod异常

历史

VisualBasic以支持早期和后期绑定而闻名,但由于它的其他限制,它从未被认为是真正的动态语言。同时,7之前的版本(又称VB.NET)对强制早期绑定的支持非常差,因此也很难将其称为静态语言

在.NET4中,可以说C#和VB都提供了静态和动态类型语言所需的大部分功能


有一次,Java被错误地称为具有后期绑定支持,而实际上它只有早期绑定的OOP风格的V表。这些年来,这引起了相当多的混乱

如Joshua所解释的,对虚拟方法的调用可能是早期绑定的(即编译器可以看到对象的确切类型,没有多态性),也可能是通过v表进行的

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

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

编辑以解决新问题:

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


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

我不确定C#是否是正确的标记,因为C#至少在加载时间之前不会进行任何绑定。嗨,我已经编辑了我的初始帖子。。。以防你发现时间古玩命名约定。vt++查找是C++中后期绑定的唯一形式。函数指针和V-TABLE一样迟,并且没有一个接近动态链接的延迟(它不承认是标准C++语言的一部分,但仍然被大量C++工具链支持)嗨,我已经编辑了我的初始文章…万一你有时间
A a=new A();
a.M();