http://www.cnblogs.com/xiaoyusmile/archive/2012/03/11/2390178.html
先看这个:
=====
总结:
这个例子就很好,函数参数就是父类。这个函数就是一种不依赖与具体类型的代码,就算以后增加类型,这个函数不变的:
可以写出不依赖于类型的code。 举例子就举基类作为函数参数的。这个基类再新加子类,这个函数也不变。例如thinking in java里的几何图形的例子
void doSomething(Shape shape) {
shape.erase();
//...
shape.draw();
}
你这可以写出下面的code:
Circle circle = new Circle();
Line line = new Line();
Triangle triangle = new Triangle();
doSomething(circle);
doSomething(line);
doSomething(triangle);
其实这是一个相对令人惊奇的诀窍。
以后别再拿Shape circle = new Circle()举例子的,得拿基类类型做函数参数的函数来举例子。
就可以让所有传给它的飞机(plane的子类对象)正常起飞!不管是直升机还是喷气机,甚至是现在还不存在的,以后会增加的飞碟。因为,每个子类都已经定义了自己的起飞方式。
多态是什么,是:就是父类 = 子类。parent = child。 如果说是什么,那就是这个。 多态的本质就是将子类类型的指针赋值给父类类型的指针(在OP中是引用),只要这样的赋值发生了,多态也就产生了,因为实行了“向上映射”。
正是基于这个,就可以写出不依赖于类型的code。
====
我们知道,封装可以隐藏实现细节,使得代码模块化;继承可以扩展已存在的代码模块(类);它们的目的都是为了――代码重用。 那么,多态的作用是什么呢?多态是为了实现另一个目的――接口重用!而且现实往往是,要有效重用代码很难,而真正最具有价值的重用是接口重用,因为“接口是公司最有价值的资源。设计接口比用一堆类来实现这个接口更费时间。而且接口需要耗费更昂贵的人力的时间。”
其实,继承的为重用代码而存在的理由已经越来越薄弱,因为“组合”可以很好的取代继承的扩展现有代码的功能,而且“组合”的表现更好(至少可以防止“类爆炸”)。因此笔者个人认为,继承的存在很大程度上是作为“多态”的基础而非扩展现有代码的方式了。
(就算以后扩展出一个新的类型,这个基于基类的函数(参数是基类类型)根本不需要任何改动)
什么是接口重用?我们举一个简单的例子,假设我们有一个描述飞机的基类(Object Pascal语言描述,下同):
type
plane = class
public
procedure fly(); virtual; abstract; //起飞纯虚函数
procedure land(); virtual; abstract; //着陆纯虚函数
function modal() : string; virtual; abstract; //查寻型号纯虚函数
end;
然后,我们从plane派生出两个子类,直升机(copter)和喷气式飞机(jet):
copter = class(plane)
private
fModal : String;
public
constructor Create();
destructor Destroy(); override;
procedure fly(); override;
procedure land(); override;
function modal() : string; override;
end;
jet = class(plane)
private
fModal : String;
public
constructor Create();
destructor Destroy(); override;
procedure fly(); override;
procedure land(); override;
function modal() : string; override;
end;
现在,我们要完成一个飞机控制系统,有一个全局的函数 plane_fly,它负责让传递给它的飞机起飞,那么,只需要这样:
procedure plane_fly(const pplane : plane);
begin
pplane.fly();
end;
就可以让所有传给它的飞机(plane的子类对象)正常起飞!不管是直升机还是喷气机,甚至是现在还不存在的,以后会增加的飞碟。因为,每个子类都已经定义了自己的起飞方式。
可以看到 plane_fly函数接受参数的是 plane类对象引用,而实际传递给它的都是 plane的子类对象,现在回想一下开头所描述的“多态”:多态性是允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。
很显然,parent = child; 就是多态的实质!因为直升机“是一种”飞机,喷气机也“是一种”飞机,因此,所有对飞机的操作,都可以对它们操作,此时,飞机类就作为一种接口。
多态的本质就是将子类类型的指针赋值给父类类型的指针(在OP中是引用),只要这样的赋值发生了,多态也就产生了,因为实行了“向上映射”。
应用多态的例子非常普遍,在Delphi的VCL类库中,最典型的就是:TObject类有一个虚拟的Destroy虚构函数和一个非虚拟的Free函数。Free函数中是调用Destroy的。因此,当我们对任何对象(都是TObject的子类对象)调用 .Free();之后,都会执行 TObject.Free();,它会调用我们所使用的对象的析构函数 Destroy();。这就保证了任何类型的对象都可以正确地被析构。
===============
java编程思想里
===========
拓展:
c语言可以模拟多态,使用结构体里的指针函数实现的。结构体相当于类。这样只提供给上层用户结构体,实现了接口与实现(库)的分离。利用指针函数还可以写出不依赖与具体类型的统一code。就是写code时利用库提供的结构体去写函数, 在最开始的时候有个给结构体初始化的过程,只要结构体的指针函数初始化不同的函数,虽然和多态不一样(子类复制给父类),但同样达到了可以写出不依赖于类型的code。所以,准确的说,不是c模拟了多态,是用结构体指针函数也写出了不依赖与类型的code。
======================
java中的多态:
写出这样完全按照A类型的code,很统一,如果想在这样的code里用一下子类独有的函数怎么办,可以用instanceof实现: