请解释 C# 中虚方法表的概念,并说明它在多态方法调用过程中起到的具体作用。
考察说明
考察对 C# 虚方法分派机制与多态实现原理的理解。
回答思路
- 【回答框架 1】虚方法表是每个类型在运行时持有的一个数据结构,按继承层次保存该类所有虚方法(含覆盖后的)的实际入口地址,是 C# 实现运行时多态(动态分派)的核心机制。
- 【回答框架 2】当调用虚方法时,编译器生成的 IL 使用 callvirt 指令,依据对象的实际类型引用去查询其虚方法表,从中取出对应方法入口并执行,从而实现基类引用调用子类覆盖版本。
- 【回答框架 3】每个类型(包括子类)的虚方法表会复制基类表项,覆盖的方法替换为子类实现,新增虚方法追加到表尾,未覆盖的基类方法保持原地址,保证继承链上的分派正确性。
- 【回答框架 4】执行时,对象头中通常包含指向其类型元数据的指针,进而找到所属类型的虚方法表,因此分派开销是两次间接寻址加一次调用,相比非虚调用稍高,但支撑了面向对象的扩展性。
- 【回答框架 5】多态调用依赖虚方法表实现动态绑定;对于非虚方法或密封方法,编译器在编译期直接解析地址,不经过虚方法表,这是性能与灵活性之间的权衡。
- 【关键点 1】虚方法表按类型保存虚方法入口地址,支持运行时动态分派。
- 【关键点 2】callvirt 指令配合对象实际类型查表实现多态调用。
- 【关键点 3】子类虚方法表继承并替换基类对应表项。
- 【关键点 4】非虚方法编译期绑定,不查虚方法表。
- 【关键点 5】分派开销为两次间接寻址加调用,性能略低于直接调用。
- 【易错点 1】混淆虚方法表与接口映射表(interface map),接口分派机制另有实现细节。
- 【易错点 2】误认为所有方法都走虚方法表,实际仅虚方法(virtual/override)触发表查找。
- 【易错点 3】忽视密封方法或类对分派性能的优化,密封后编译器可转为直接调用。