多态

很多人常把多态和继承混淆起来,实际上二者区别较大,一个明显的例证便是,VB 6.0中没有继承,但有多态。一般的理解是,继承强调的是自上而下的\"血缘关系",是"是一个""是一种"的关系;而多态只强调两个对象在行为上的相似性,而不管这两个对象之间是什么关系。有继承关系的对象一般都有多态关系,而有多态关系的对象间未必有继承关系。比如,马有跑的行为,蒙古马和伊犁马都是马的一种,它们都与马有继承关系,都有跑这个行为,在\"跑\"这个意义上,它们有多态关系。同样,机器猫也能跑,机器猫与马在跑这个行为上有多态关系,但它们没有继承关系。

VB 6.0中有两种方法可以实现多态,即后期绑定和接口。在本套书的VB篇中我们大量采用了接口这种方法来实现多态。在性能上,它比用后期绑定实现要好些。.NET 中还可以通过继承和.NET 反射来实现多态,下面主要介绍继承和接口这两种实现途径。

用继承实现多态

在2.2节介绍继承时创建了基类CGElement和派生类CLine。下面再创建一个派生类CRectangle。CRectangle类用于定义矩形的特征和方法。为了演示多态,这里只添加一个无参构造函数和一个Drw方法。Daw方法重 了基人的Draw方法。

【VB.NET】

code.vb.net
Public Class CRectangle
    Inherits CGElement
    Public Sub New()
    End Sub
    Public Overrides Sub Draw()
        text-blue-400">Console.text-blue-400">WriteLine("绘矩形。")
    End Sub
End Class

【VC#.NET】

code.vc#.net
public class CRectangle:CGElement
{
    public Crectangle()
    {
    }
    public override void Draw()
    {
        Console.WriteLine("绘矩形。"):
    }
}

然后在Form1类中添加下面的代码,创建两个CGElement类型的变量并分别作为一个CLine人实例和一个CRectangle子例的引用,然后调用CGElement 的 Drw方法绘制直线段和矩形。

【VB.NET】

code.vb.net
Private Sub Form1_Load(ByVal sender As System.0bject,
            ByVal text-blue-400">e As System.EventArgs) Handles MyBase.Load
    Dim ge1 As CGElement = New CLine()
    Dim ge2 As CGElement = New CRectangle()
    gel.Draw()
    ge2.Draw()
End Sub

【VC#.NET】

code.vc#.net
private void Form1_Load(object sender, System.EventArgs e)
{
    CGElement ge1= new CLine();
    CGElement ge2= new CTectangle();
    ge1.Draw();
    ge2.Draw();
}

程序运行结果如图2-4所示。可见,由于实现了多态,可以自动区分是绘制直线段还是绘制矩形。

Document Image
\[\]

图2-4用继承实现多态

2.4.2用接口实现多态

沿用2.3节的例子,仿照2.4.1节添加CRectangle类,它实现了IGElement接口。

【VB.NET】

code.vb.net
Public Class CRectangle
    Implements IGElement
    Private m_ID As Integer
    Public Property ID() As Integer Implements IGElement,ID
        Get
            Return m_ID
        End Get
        Set(ByVal Value As Integer)
            m_ID =Value
        End Set
    End Property
    Public Sub Draw() Implements IGElement.Draw
        text-blue-400">Console.text-blue-400">WriteLine("绘矩形。")
    End Sub
End Class

【VC#.NET】

code.vc#.net
public class CRectangle:IGElement
{
    private int m_ID;
    public int ID
    {
        get{retum m_ID;}
        set{m_ID = value:}
    }
    public void Draw()
    {
        Console.WriteLine("绘矩形。");
    }
}

在Form1类中添加下面的代码,对实现了IGElement接口的类进行测试。

【VB.NET】

code.vb.net
Private Sub Form1_Load(ByVal sender As System.Object,
            ByVal text-blue-400">e As System.EventArgs) Handes MyBase.Load
    Dim ge1 As IGElement = New CLine()
    Dim ge2 As IGElement = New CRectangle()
    ge1.ID=1
    ge2.ID =11
    text-blue-400">Console.text-blue-400">WriteLine("ID:{0},{1}", ge1.ID,ge2.ID)
    ge1.Draw()
    ge2.Draw()
End Sub

【VC#.NET】

code.vc#.net
private void Form1_Load(object sender, System.EventArgs e)
{
    IGElement ge1= new CLine();
    IGElement ge2=new CRectangle();
    ge1.ID=1;
    ge2.ID=11;
    Console.WriteLine("ID:{0},{1}", ge1.ID, ge2.ID);
    ge1.Draw();
    ge2.Draw();
}

程序运行结果如图2-5所示。可见,利用接口也能很好地实现多态。

Document Image
\[\]

图2-5 用接口实现多态

两种方式的比较

上面两种方式都能实现多态,而且性能相近。一般来说,当对象存在继承关系时用继承实现多态,不存在继承关系时用接口实现多态。