图3 对象名、对象与类的关系
DMT和VMT类似,也是逻辑上的一个概念,不同的是,在类中只保存了自身动态方法指针,而没有基类的动态方法的地址,这样就节省了一些内存,但速度不如虚方法,是一种牺牲时间换空间的策略,一般情况不推荐使用。
引用上面的例子来解释一下:
Employee[i].startWorking;
Employee[i]是一个基类Temployee的对象引用,有上面的程序知道,它可能指向了一个Tprogramer对象,也可以可能指向一个TbusinessMan,还有可能是其他的对象,而且这些都是不确定的、动态的,所以在编译时无法知道实际的对象,也就无法确定方法地址。而在运行期,当然知道对象的“庐山真面目”了,根据实际对象的首四个字节的内容,也就是虚拟方法表VMT的入口地址,找到实际要调用的函数,即实现了多态。
1.3.3 重载(Overload)与多态
很多网友认为函数重载也是一种多态,其实不然。对于“不同的操作”,重载无法提供同一的调用的方式,虽然函数名相同,但其参数不同!实现多态的前提,是相同的表达式!如Employee[i].startWoring,而重载的调用,有不同的参数或参数类型。重载只是一种语言机制,C语言中也有重载,但C语言没有多态性,C语言也不是面向对象编程语言。除非重载函数同时还虚方法,不然编译器就可以根据参数的类型就可以确定函数的入口地址了,还是静态绑定!引用C++之父的话“不要犯傻,如果不是动态绑定,就不是多态”。
1.4多态种类的探讨
1.4.1 两级多态
对象级:用基类指针/引用指向其派生类对象,调用虚方法(或动态方法、抽象方法),这是用的最多一种。
类级:用类引用(指向类而不是对象的引用)指向派生类,调用虚类方法(或动态类方法、抽象类方法),常用在对象创建的多态性(因为构造方法是一种“特殊的”类方法,请参考我的另一篇拙作《剖析Delphi中的构造和析构》,第2.1节)。
延伸阅读
文章来源于领测软件测试网 https://www.ltesting.net/