多态
多态是面向对象理论中至关重要的概念。它关注的是对象行为方面的问题,在派生关系中的对象的行为发生变化,这就是所谓的多态性。
我们本节的代码基本用C++代码作为例子(因为我们有机会深入到虚表去论证一些重要的问题,尽管也许没有这个必要),而对于Java开发者或是C#的开发者来说,也都是可以理解和接受的。我们依然以Button作为例子:
{
public :
virtual void OnDraw()
{
/* code for drawing a Button */
}
};
class ImageButton : public Button
{
public :
virtual void OnDraw()
{
/* code for drawing an ImageButton */
}
};
这里,依然是ImageButton类继承了Button类,并且重写 (override)了基类中的虚函数 OnDraw ();。这是什么意思呢?从设计的角度来说,当我们设计Button类的时候,当然不能确定将来会有什么样的派生类出现,但是,一个未知的派生类 Button显然有自己的风格,样式,或者说外观,也就是说有其自己的显示方式,于是,我们在设计Button类的时候,就让OnDraw()方法为 virtual方法。而对于Java来说,一个非private和非final的方法,就等同于virtual方法了。这意味着,尽管我们在编写 Button类的时候不知道将来会出现什么样式的Button,但是已经知道(预计)它(可能)会有自己的绘制行为了。
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
pButton -> OnDraw();
// Code will go into ImageButton::OnDraw(), not Button::OnDraw().
那么上面的代码完整地展示了多态的工作情况,我们用基类的指针变量调用了派生类的方法,那么这种行为就叫做多态。这是多态在具体编程语言上的表述和体现。
通常,比较完整的说法是:“用基类的指针或者引用变量去调用派生类对象的实例方法。”
在这里,我们需要强调的是,“用基类的指针或者引用”,因为这是多态所以关键的因素。比如下面的代码,于运行之前,我们无从知道基类的指针到底是指向了哪一个派生类的对象,也许是一个ImageButton类的对象,也许是一个CheckButton类的对象实例。
{
Button->OnDraw();
//Who knows, what's the type of the instance which pButton points to.
}
但是,尽管我们不知道pButton指针指向的对象的实际类型(我指的是在编译期),但是这段代码却是可以通过编译,并且顺利运行,而具体会呈现出什么行为,完全是由运行时实际指向对象的类型决定的,这就是动态绑定,或者称为延迟绑定。
理解多态至关重要,它的运用非常广泛,也非常灵活,它是面向对象中最核心和最基础的概念。我们在这节中只讲最基本的概念和语法。但是在后续的章节中,我们会更加深入的讨论多态。多态将贯通整个专题。
我们所要讲的是多态的理论,而不是实现,我们暂时不会涉及到C++的虚表,或者JVM的invokevirtual指令,这些细节似乎并不能帮助我们理解多态理论的运用和对象设计。但是需要的时候,我会以ASM的角度来阐述面向对象多态的实现细节。