今天看了才真正的明白什么是多态性,其实就是覆盖。基类中有一个方法,必须是虚方法,在其子类中用override进行覆盖。
在静态方法中,定义一个和基类一样的方法,一个变量为基类类型,子类对象对其赋值,方法为基类方法,只有变量为子类类型方法才是子类方法,但用override覆盖后,对象是什么类就用什么类的方法。
摘录了一篇文章
多态的概念与接口重用
首先,什么是多态(Polymorphisn)?按字面的意思来讲,就是“多种形状”。笔者也
没有找到对多态的非常学术性的描述,暂且引用一下Charlie Calvert对多态的描述——多态
性是允许用户将父对象设置成为与一个或更多的它的子对象相等的技术,赋值之后,基类
对象就可以根据当前赋值给它的派生类对象的特性以不同的方式运作。
更简单地说就是:多态性允许用户将派生类类型的指针赋值给基类类型的指针。多态
性在Object Pascal中是通过虚方法(Virtual Method)实现的。
什么是“虚方法”?虚方法就是允许被其派生类重新定义的方法。派生类重新定义基
类虚方法的做法,称为“覆盖”(override)。
这里有一个初学者经常混淆的概念:覆盖(override)和重载(overload)。如前所述,
覆盖是指派生类重新定义基类的虚方法的方法。而重载,是指允许存在多个同名函数,这
些函数的参数表不同(或许是参数个数不同,或许是参数类型不同,或许两者都不同)。
重载的概念并不属于“面向对象编程”。重载的可能的实现是:编译器根据函数不同的参
数表,对同名函数的名称做修饰,然后这些同名函数就成了不同的函数(至少对于编译器
来说)。例如,有两个重载的同名函数
function func(p : integer) : integer; overload;
function func(p : string) : integer; overload;
那么编译器做过修饰后的函数名可能是:int_func、str_func。如果调用
func(2);
func(′hello′);
那么编译器会把这两行代码分别转换成:
int_func(2);
str_func(′hello′);
这两个函数的调用入口地址在编译期间就已经静态(记住:是静态!)确定了。这样
的确定函数调用入口地址的方法称为早绑定。
而覆盖则是:当派生类重定义了基类的虚方法后,由于重定义的派生类的方法地址无
法给出,其调用地址在编译期间便无法确定,故基类指针必须根据赋给它的不同的派生类
指针,在运行期动态地(记住:是动态!)调用属于派生类的虚方法。这样的确定函数调
用地址的方法称为晚绑定。引用一句Bruce Eckel的话:“不要犯傻,如果它不是晚绑定,
它就不是多态”。
..注意:重载只是一种语言特性,与多态无关,与面向对象也无关!
多态是通过虚方法实现的,而虚方法是通过晚绑定(或动态绑定)实现的。
其次,多态的作用是什么呢?前两节已经讲到,封装可以隐藏实现细节,使得代码模
块化;继承可以扩展已存在的代码模块,它们的目的都是为了代码重用。而多态则是为了
实现另一个目的——接口重用。
什么是接口重用?举一个简单的例子,假设有一个描述飞机的基类:
type
TPlane = class
protected
FModal : String; // 型号
public
procedure fly(); virtual; abstract; // 起飞抽象方法
procedure land(); virtual; abstract; // 着陆抽象方法
function modal() : string; virtual; // 查寻型号虚方法
…… // 其他可能的操作
end;
然后,从TPlane派生出两个派生类,直升机(TCopter)和喷气式飞机(TJet):
TCopter = class(TPlane)
public
constructor Create();
destructor Destroy(); override;
procedure fly(); override;
procedure land(); override;
function modol() : string; override;
…… //其他可