VMT中。如图2.6所示,直升机类(TCopter)覆盖了其基类(TPlane)的虚方法fly()和land(),
因此在TCopter的VMT中,fly和land被确定为TCopter的实现方法的入口地址。但由于
TCopter没有覆盖TPlane的虚方法modal(),则在VMT的modal()项中被填入了TPlane.modal()
的入口地址,即基类中该方法的入口地址。
被派生类覆盖的方法,则会将派生类实现的方法的入口地址填入VMT中以取代基类
被覆盖的方法。
这就是“晚绑定”或“动态绑定”!
对照图2.6来看,当基类类型的指针指向了直升机实例对象后,可以通过基类类型的
指针来让这架直升机起飞:
plane.fly();
编译器通过plane所指对象的“指向VMT的指针”可以定位到TCopter.fly()的地非曲
直址,由此便可以找到属于直升机的fly()方法,而得以以直升机的起飞方式来让一架直升
机起飞。
虽然动态绑定看起来并不太复杂,但意义重大!如果没有动态绑定,那么,试想一下,
以喷气式飞机的起飞方式来让一架直升机起飞会发生什么?这可关系到飞行员的安全啊。
到这里,读者对动态绑定的实现应该清楚了。细心的读者可能又会发现一个问题,
TPlane中的析构函数也是virtual的,为什么没有出现在VMT中呢?
当然,并非VMT中没有析构函数,只能说它没有出现在我们所能见到的VMT中。之
前所说的“指向VMT的指针”所指向的VMT,其实只是真正的VMT的一部分,也就是
用户定义的第一个虚方法的位置。如果以这个位置作为原点,向正方向即刚才所说的VMT。
而向负方向,则是语言定义的另一些类信息所在的地址,析构函数地址就被放在了负方向
上了。
Delphi之所以这么做,是为了使得Object Pascal的VMT与C++的以及COM的vtable(虚函数表)兼容。
这里给出完整的VMT的地址表(来自Delphi6 Help),不过这些内容仅能作为参考,
因为Borland并不承诺将来不会改变这个格式,如表2.1所列。
表2.1 Delph6 VMT
偏移地址
类 型
描 述
-76
Pointer
pointer to virtual method table (or nil)
-72
Pointer
pointer to interface table (or nil)
-68
Pointer
pointer to Automation information table (or nil)
-64
Pointer
pointer to instance initialization table (or nil)
-60
Pointer
pointer to type information table (or nil)
-56
Pointer
pointer to field definition table (or nil)
-52
Pointer
pointer to method definition table (or nil)
-48
Pointer
pointer to dynamic method table (or nil) (指向DMT的指针)
-44
Pointer
pointer to short string containing class name
-40
Cardinal
instance size in bytes
-36
Pointer
pointer to a pointer to ancestor class (or nil)
续表
偏移地址
类 型
描 述
-32
Pointer
pointer to entry point of SafecallException method (or nil)
-28
Pointer
entry point of AfterConstruction method
-24
Pointer
entry point of BeforeDestruction method
-20
Pointer
entry point of Dispatch method
-16
Pointer
entry point of DefaultHandler method
-12
Pointer
entry point of NewInstance method
-8
Pointer
entry point of FreeInstance method
-4
Pointer
entry point of Destroy destructor
0
Pointer
entry point of first user-defined virtual method
4
Pointer
entry point of second user-defined virtual method
可以看到,偏移地址-28 ~ -4所存放的都是TObject的虚方法地址,当然析构函数也在
其中。
最后,有必要再谈一下Object Pascal所独有的DMT(动态方法表)。
在表2.1的偏移地址为-48处是一个指向DMT的指针,它是干什么用的?它和VMT
有什么关系?
在VMT中可以看到,派生类的虚方法表完全继承了基类的虚