日期:2008-05-14  浏览次数:20388 次

实例看多态



近来看了一下多态性,把我的一些感受以例子的形式记录一下。



一.形象理解

两条理解的原则:
(1)一个派生类对象可以被声明成一个基类,或者是一个基类指针可以指向一个派生类对象:
//c++ code

BaseClass *p;

DerivedClass obj;

p = &obj;



//C# code

BaseClass obj = new DerivedClass();


(2)把一个对象看做是一个独立的个体,调用对象的public成员函数实际上是给这个对象发送一个消息,采取什么样的动作完全由对象自己决定。



Shape是基类,Circle和Line是从Shape继承出来的,Shape有draw()方法,Circle与Line分别自己定义了自己的draw()方法,在下面的代码里:

// Java Code

static void func(Shape s)

{

s.Draw();

}

如果发生了这样的调用:

Line l = new Line();

Circle c = new Circle();

func(l);

func( c);

一个Circle和一个Line被当做Shape传到函数里去了,然后调用Draw(),会发生什么情况?因为对象是独立的个体,在func()里,这两个对象被分别传递了Draw()消息,叫它们绘制自己吧,于是他们分别调用了自己类里定义的Draw()动作。



通过这两条原则我们可以理解上面的多态。正是由于多态,使得我们不必要这样去做:

IF 你是一个Circle THEN 调用Circle的Draw()

ELSE IF 你是一个Line THEN 调用Line的Draw()

ELSE …

我们只要给这个被声明成为Shape的对象发送Draw消息,怎么样去Draw就由对象自己去决定了。



二.一切皆因虚函数



先看看实现多态的基本条件:

(1) 基类含有虚函数

(2) 继承类把这个虚函数重新实现了

(3) 继承类也可能没有重新实现基类的所有虚函数,因此对于这些没有被重新实现的虚函数不能发生多态。



再看一下几种语言里一些特别的规定:

1. C++:
(1)虚函数用virtual关键字声明。
(2)virtual void Func(para_list) = 0;这样的虚函数叫做纯虚函数,表示这个函数没有具体实现。包含纯虚函数的类叫做抽象类,如果他的继承类没有对这个纯虚函数具体用代码实现,则这个继承类也是抽象类。抽象类不能被实例话(就是说不能创建出对象)。
(3)继承类重新实现基类的虚函数时,不需要做任何特别的声明。
(4)如果不用virtual关键字修饰,并且在派生类里重新实现了这个方法,这仅仅是一个简单的覆盖,不会发生多态,我们暂称它非多态吧。



2. Java:
(1)Java没有virtual关键字,Java把一切类的方法都认为是虚函数。
(2)继承类重新实现基类的虚函数时,不需要做任何特别的声明。因此在Java里只要重新实现了基类的方法,并且把继承类对象声明为基类,多态就要发生。因此Java对多态的条件相对是比较低的。

//Java Code
class BaseClass
{
public void hello(){};
}

class DerivedClass extends BaseClass
{
public void hello()
{
System.out.println(“Hello world!”);
}

public static void main(String args[])
{
BaseClass obj = new DerivedClass();
obj.hello();
}
}

输入是Hello world!。这样就实现了多态。

(3)虚函数用abstract声明,含有虚函数的类是抽象类,也要用abstract关键字修饰。

//Java Code
public abstract AbstractClass
{
public abstract void hello();
//…
}



3. C#:
C#对于多态的编写是最为严格和严谨的。
(1)虚函数用virtual声明。
(2)纯虚函数用abstract声明,含纯虚函数的类是抽象类,必须用abstract关键字修饰。
(3)如果仅仅是覆盖基类的非虚方法,则需要用new关键字声明:
//C# Code
public class BaseClass
{
public void hello()
{
System.Console.WriteLine(“Hello,this come from BaseClass”);
}
}

public class DerivedClass : BaseClass
{
public new void hello()
{
System.Console.WriteLine(“Hello,this is come from DerivedClass”);
}

public static void Main()
{
BaseClass obj = new DerivedClass();
obj.hello();
}
}

输出为Hello,this come from BaseClass,也就是说这并没有实现多态(非多态)。

(4)通过virtual – override、abstract – override组合实现多态。
当派生类重新实现基类的虚函数(或纯虚函数)时,必须用override关键字进行修饰。

//C# Code
public abstract class AbsBaseClass
{
public abstract void hello();
}

public class DerivedClass : AbsBaseClass
{
public void hello()
{
System.Console.WriteLine(“Hello world!”);
}

public static void SayHello(AbsBaseClass obj)
{
obj.hello();
}

public static void Main()
{
DerivedClass _obj = new DerivedClass();
DerivedClass.SayHello(_obj);
}
}

输出为Hello world!



三.多态的反溯
继承