类是描述对象特征的代码。作为对象来说,一方面它有很多自身的特点,有一些固有属性,另一方面,它要与其他对象进行交互,发生联系,会产生一系列的行为。而且,当某种行为发生在它上面时,可能会发生一些事件,产生一定的后果。所以,用代码来描述对象时,就需要考虑这些问题,并进行抽象、概括和组织。本节主要介绍类的相关概念和实现方法。

属性

属性描述对象的特征,它是一种特殊的方法,用于设置和读取对象的值。下面创建一个CPosition类,它有一个x属性和一个y属性,分别定义点的横坐标和纵坐标,定义代码如下:

【VB.NET】

code.vb.net
Public Class Position
     Private m_x, m_y As Single
     Private m_ID As Integer
     Public Property x() As Single
          Get
               Return m_x
          End Get
          Set(ByVal Value As Single)
               m_x=Value
          End Set
     End Property
     Public Property y() As Single
          Get"
               Return m_y
          End Get
          Set(ByVal Value As Single)
               m_y = Value
          End Set
     End Property

【VC#.NET】

code.vc#.net
public class Positior
{
     private float m_x,m_y;
     private int m_ ID;
     public float x
     {
          get{return m_x;}
          set{m_x= value;}
     }
     public float y
     {
          get{return m_y:}
          set{m_y = value;}
     }

从上面的代码中可以看出,在VB.NET代码中,读写属性的语句是集中在一个过程中的,这与VB 6.0中不同。在VB 6.0中,读写属性使用各自的属性过程。相比而言,现在的形式更紧凑,更便于阅读。

只读属性

有的属性值可以由其他基本属性值获得,是只读的,称为只读属性。在VB.NET和VC#.NET中,在属性过程中添加 ReadOnly关键字,并且只实现Get块,可以实现只读属性。例如,假设坐标原点为(0,0),则在同一坐标系中,当前点到原点的距离可以求得,把它设置为Disto属性,编码为:

【VB.NET】

code.vb.net
Public ReadOnly Property Disto() As Double
     Get
          Return text-blue-400">Sqrt(m_x * m_x+m_y * m_y)
     End Get
End Property"

【VC#.NET】

code.vc#.net
public float Disto
{
     get{return(float)(Math.Sqrt(m_x*m_x+m_y*m_y));}
}

2. 只写属性

与只读属性相对应,有的属性是只写的。在属性过程中添加WriteOnly关键字,并且只实现Set块,可以实现只写属性。

3. 缺省属性

如果是用VB.NET编程,用Default关键字来标示属性时该属性定义为缺省属性。现在假设创建了一个CPoints类,它能够保存CPosition对象并能实现索引和删除。为了实现索引,定义了一个Item属性,它是一个缺省的只读属性,其中alD为索引值。该方法返回一个CPosition对象。

【VB.NET】

code.vb.net
Default Public ReadOnly Property Item(ByVal aID As Integer) As Position
     Get
          '返回一个CPosition类型的对象
     End Get
End Property

如果用VC#.NET 编程,要定义缺省属性则需要使用索引器,如下所示:

【VC#.NET】

code.vc#.net
public Position this {int aID}{
     get{
          //返回一个CPosition类型的对象
     }
}

将属性定义为缺省属性以后,可以在类实例名称后面直接跟括号和索引值。例如,现在clines是一个CLines类实例,其中存储了10个CLine对象,则可以通过clines(4)的方式直接调用其中的第5个对象。

方法

方法是一些函数和过程。根据需要,可以创建公共方法、受保护的方法和私有方法等,它们具有不同的使用范围。

1. 公共方法

公共方法用Public或pu blic关键字进行标示,在整个项目范围内都可以使用。下面给Position类添加一个GetAngle方法,它返回当前点与坐标原点间的方位角。

【VB.NET】

code.vb.net
    Public Function GetAngle(ByVal p1 As PointF) As Single
        '…
    End Function

【VC#NET】

code.vc#.net
		public float GetAngle(PointF p1){
			//…
		}

2. 受保护的方法

受保护的方法用Protected或protected关键字进行标示,可以用于本类及其派生类。受保护的方法就像那些只在特定系统或部门内适用的法规、规则一样。

3. 私有方法

在函数或过程前添加Pivate关键字,将方法设置为私有。私有方法只能被六类中的函数或过程所调用,是为其他函数服务的。比如,在交互绘制圆弧的过程中,拾取圆弧时需要知道拾取点是否落在圆弧所在的范围内,可通过比较拾取点、圆弧起点和终点这三点的方位角的关系来实现。此时,就要用到前面的GetAngle函数,它在这里是私有的。因为在外部调用圆弧类CArc的方法时不会用到它,它是为Pick方法服务的。可用下面的代码将方法设置为私有。

【VB.NET】

code.vb.net
Public Class Carc
     '…
     Public Function Pick(Byval aPos As PointF,
                    Byval PickRadius As Single)
                    As Boolean
          '…
          angBegin=GetAngle(m_Begin)
          angEnd=GetAngle(m_End)
          angCur=GetAngle(aPos)
          '…
     End Function
     Private Function GetAngle(Byval aPos As PointF) As Single
          '…
     End Function
     '…
End Class"

【VC#.NET】

code.vc#.net
public class CArc
{
     //…
     public bool Pick(PointF aPos,float PickRadius)
     {
          //…
          angBegin=GetAngle(m_Begin);
          angEnd=GetAngle(m_End);
          angCur=GetAngle(aPos);
          //…
     }
     private float GetAngle(PointF aPos)
     {
          //…
     }
}

构造函数

构造函数是VB.NET新增的功能,VB6.0里面没有。它的主要作用是提供对象数据的初始化。可以提供一个构造函数,也可以提供多个构造函数。

1. 创建无参构造函数

无参构造函数没有参数,每个类都有一个无参构造函数。下面给前面创建的CPositon类添加无参构造函数。用VC#.NET创建类时,会自动给出一个无参构造函数。

【VB.NET】

code.vb.net
Public Sub New()
End Sub

【VC#.NET】

code.vc#.net
public position(){
}

2. 带参构造函数

构造困数可以带一个或多个参数。一般而言,类中应该提供尽可能全面的构造要 。下面给Position类提供两个构造函数,一个用给定的横、纵坐标定义,另一个用已经存在的点来定义。

【VB.NET】

code.vb.net
Public Sub New(By Val xx As Single, By Val yy As Single)
     m_x=XX
     m_y =yy
End Sub
Public Sub New(ByVal aPos As Position)
     With aPos
          m x=.x
          m y=.y
     End With
End Sub

【VC#.NET]

code.vc#.net
public Position(float xx,float yy)
{
     m_x=xx;
     m_y=yy;
}
public Position(Position aPos)
{
     m_x=aPos.x;
     m_y =aPos.y;
}

重载

重载允许我们使用参数不同但名称相同的方法。假如前面定义了多个构造函数,过程名称都相同,但参数个数或类型不同,这实际上也是一种重载。在VB6.0里面不能实现重载,同一个类中不允许有名称相同的方法。

使用重载时可以有几种情况,一种是参数个数不相同,另一种是参数个数相同,但参数类型不全相同。为了演示重载,下面给Position类添加一组重载方法Move。第1个Move方法使当前点水平移动,第2个Move方法使当前点可以向平面上任何方向移动。

【VB.NET】

code.vb.net
Public Sub Move(ByVal deltaX As Single)
     m_x+=deltax
End Sub
Public Sub Move(ByVal deltaX As Single, ByVal deltaY As Single)
     m x+=deltaX
     m_y+=deltaY
End Sub"

【VC#.NET】

code.vc#.net
public void Move(float deltaX)
{
     m_x+=deltaX;
}
public void Move(float deltaX, float deltaY)
{
     m x+=deltaX;
     m_y+=deltaY;
}

定义重载方法以后,调用时会显示黄色提示信息框。信息框中,前面是一个上下框,其中给出了重载方法的总个数和当前方法的序号;后面显示的是当前方法的调用格式。单击上下框两侧的箭头按钮,可以进行滚动,显示上一个或下一个方法的调用格式。

Me和this

在VB.NET和VC#.NET中,分别用Me和this调用自身成员。下面在两种语言的Position类中分别添加MeTest方法和 thisTest方法,在输出窗口输出当前点的坐标。

【VB.NET】

code.vb.net
Public Sub MeTest()
     text-blue-400">Console.text-blue-400">WriteLine("坐标为:{0),{1)", Me.x, Me.y)
End Sub

【VC#.NET】

code.vc#.net
public void thisTest()
{
     Console.WriteLine("坐标为:[0),{1)", this.x, this.y);
}

应用Position类

为了说明类的创建,前面定义了一个Position类,包括它的属性、方法和构造函数等。下面对它进行测试,说明如何调用它的成员。在项目的Form1类中添加Form1 Load事件代码,在载入窗体时创建3个Position对象,然后在输出窗口中输出它们的坐标值。后面还测试了GetAngle方法和重载方法Move。

【VB.NET】

code.vb.net
Private Sub Form1_Load(ByVal sender As System.Object,
          ByVal text-blue-400">e As System.EventArgs) Handles MyBase.Load
     Dim aPos1 As New Position(10, 10)
     Dim aPos2 As New Position(0, 0)
     Dim aPos3 As New Position(aPos1)
     text-blue-400">Console.text-blue-400">WriteLine("坐标为:{0},{1}",aPos2.x,aPos2.y)
     text-blue-400">Console.text-blue-400">WriteLine("坐标为:{0},{1}",aPos3.x, aPos3.y)
     text-blue-400">Console.text-blue-400">WriteLine(aPos1.GetAngle0)
     aPos2.Move(100)
     aPos3.Move(100,100)
     text-blue-400">Console.text-blue-400">WriteLine("坐标为:{0},{1}",aPos2.x,aPos2.y)
     text-blue-400">Console.text-blue-400">WriteLine("坐标为:{0},{1}", aPos3.x,aPos3.y)
     aPos1.MeTestO
End Sub

(VC#.NET】

code.vc#.net
private void Forml_Load(object sender, System.EventArgs e)
{
     Position aPos1=new Position(10, 10);
     Position aPos2=new Position(0, 0);
     Position aPos3=new Position(aPos1);
     Console.WriteLine("坐标为:{0},{1}",aPos2.x,aPos2.y);
     Console.WriteLine("坐标为:{0},{1}",aPos3.x,aPos3.y);
     Console. WriteLine(aPos1.GetAngle());
     aPos2.Move(100);
     aPos3.Move(100,100);
     Console.WriteLine("坐标为:{0},{1}",aPos2.x,aPos2.y);
     Console.WriteLine("坐标为:{0},{1}",aPos3.x,aPos3.y);
     aPos1.thisTest();
}