动态分派是一种运行时机制,它根据对象的实际类型而非变量的声明类型来决定执行哪个方法实现。大多数基于类的语言通过**虚方法表(vtable)**来实现它。
虚表模型
每个类都有一个包含其方法实现指针的表。每个对象持有一个指向其类的虚表的隐藏指针。一个虚调用变成:在对象的虚表中查找该方法,然后跳转到那里。
text
Animal a = new Dog();
a.speak();
a ──▶ Dog object ──▶ [Dog vtable]
speak() ──▶ Dog.speak() ← chosen at RUNTIME
编译器不会硬编码 Animal.speak;它生成的代码是"调用该对象指向的虚表中的第 N 个槽"。
为什么声明类型不够
java
Animal a = new Dog(); // declared Animal, actual Dog
a.speak(); // → Dog.speak(), because dispatch uses the OBJECT
语言差异
陷阱
存在小的性能开销(一层间接寻址),并且它会阻止内联优化。在 C++ 中,忘记标记 virtual 意味着调用会静态绑定,覆盖会被静默地不调用——这是一个微妙的 bug。
为什么这很重要
理解分派机制解释了为什么覆盖会起作用以及为什么声明类型不决定行为——这是常见的困惑来源。
它还清晰地说明了真实的后果:虚调用的性能开销、为什么构造函数不应该调用虚方法,以及为什么 C++ 需要显式要求 virtual。
