1、以前的VB版本已经有了面向对象的概念,但并不全面。真正的面向对象语言应该支持封装、继承和多态。而随着VB.NET的引入,VB已经是一个真正的成熟的面向对象的语言了。本章将讲述VB.NET面向对象特性中最基本的类与对象。7.1 面向对象的基本概念7.2 在VB.NET中使用类7.3 创建和使用对象7.4 共享成员在面向对象的世界里,一切概念上的存在,小至单个整型数或字符串,大至由许多部件组成的系统,均可称作对象。对象是属性和行为(数据和操作)的封装体,其中还包括和其它对象进行通信的设施,而行为通常称作方法。对象按照不同的性质划分为不同的类。同类对象在数据和操作性质方面具有共性。在面向对象程序设计
2、语言中,程序由一个或多个类组成。在程序运行过程中根据需要,创建类的对象,即其实例。因此类是静态概念,对象是动态概念,类是对象之上的抽象。有了类之后,对象则是类的具体化,是类的实例。字段(field)和属性(property)都是类用于保存数据的成员。不同之处在于,字段只是类公开的简单变量,而属性可以使用属性过程控制如何设置或返回值。方法(method)也称作行为(behavior),指定义于某一特定类上的操作与法则,具有同类的对象只可为该类的方法所操作。换言之,这组方法表达了该类对象的动态性质,而对于其它类的对象可能无意义甚至非法。事件(event)是指发生的事情。对象可以响应其外部发生的某些
3、事件,以启动某些处理过程。事件驱动的应用程序是指程序的执行流程是由外部发生的事情来决定的程序。在面向对象的方法中,所有信息都存贮在对象中,即其数据及行为都封装在对象中。影响对象的唯一方式,是执行它所从属的类的方法,即执行作用于其上的操作,这就是信息隐藏(information hidding)。继承是一种使用户得以在一个类的基础上,建立新的类的技术。新的类自动继承旧类的属性和行为特征,并可具备某些附加的特征或某些限制。新类称作旧类的子类,旧类称作新类的父类。在收到消息时对象要予以响应,不同的对象收到同一消息可以产生完全不同的结果,这一现象叫做多态。同一运算符可用于不同的变量类型,称作运算符重载
4、。例如,加运算既可用来加两个整数,也可实现浮点数相加,还可以实现字符串相连,甚至可以在程序中定义复数,实现复数相加、复数和整数相加等。在这些情况下,同样的操作对于不同的参数类型会保持运算功能的透明性。同一方法可作用于不同对象上,并产生不同的结果。例如,OPEN方法既可作用于数据流,也可作用于窗口等。在VB.NET中创建类是很容易的,可以有以下3种方法。作为添加到“Windows应用程序”项目的一个独立类模块。作为“Windows应用程序”项目的某个窗体模块中代码的一部分。作为一个独立的“类库”项目。首先,我们新建一个应用程序工程,在【新建项目】窗口的【模板】列表框中选择【Windows For
5、m窗体应用程序】,并在【名称】文本框中输入“7-1EmployeeClass”。单击菜单栏中的【项目】【添加类】命令,打开【添加新项7-1EmployeeClass】窗口,并在【名称】文本框中输入“Employee.vb”。单击【添加】按钮后,编译器将自动为我们生成了空类的代码。类名默认与类文件名称相同,也可以进行修改。1 Public Class Employee 2 3 End Class 其中,Class关键字用于声明一个类;Public是该类的访问修饰语,表示该类是公共的,对类内的实体无访问限制;Employee是类的名称,通常选择有意义的能够说明类功能的名称。1 Public Cla
6、ss Form1 2 Form1窗体的代码 3 End Class 4 Public Class Employee 5 Employee类的代码 6 End Class通过这种方式创建的类,缺点在于这些类只在创建它们的项目中可用。单击菜单栏中的【文件】【新建项目】命令】命令,在弹出的【新建项目】窗口中的【模板】列表框中选择【类库】模板,即可创建一个类库项目。向类中添加属性可以采用字段或属性过程两种方式。还可以用属性的Public、ReadOnly或WriteOnly等修饰符确定属性如何工作。字段只是类中的公共变量,可以从该类的外部设置或读取这些变量。对于员工来说,可能会有在职人员和退休人员之分
7、,可以使用一个Boolean类型变量来表示。下面的代码为Employee类添加一个Retired字段,类型为Boolean类型,True表示退休,False表示在职。Public Retired As Boolean属性过程有存储属性值的私有变量的声明、公开该值的Get过程以及设置该值的Set过程3个部分。下面的代码为Employee类添加firstName属性,用于表示员工的姓。1 Private firstNameValue As String 2 Public Property FirstName()As String 3 Get 4 FirstName=firstNameValue 5
8、 End Get 6 Set(ByVal value As String)7 firstNameValue=value 8 End Set 9 End PropertySet(ByVal value As String)Dim i As Integer Dim numContained As Boolean=False For i=0 To 9 If value.Contains(i.ToString()Then numContained=True Exit For End If Next If numcontained=False Then firstNameValue=value Else
9、 MessageBox.Show(“First name contains number!”)End If End Set下面的代码为Employee类添加了一个只读属性ID,用于表示员工的编号。1 Private IDValue As Integer 2 ReadOnly Property ID()As Integer 3 Get 4 ID=IDValue 5 End Get 6 End Property下面的代码为Employee类添加了一个只写属性Password,用于表示员工的密码。1 Private passwordValue As String 2 WriteOnly Proper
10、ty Password()As String 3 Set(ByVal value As String)4 passwordValue=value 5 End Set 6 End Property类的方法就是在该类中声明的Sub或Function过程。例如,将员工的姓与名分开,在某些情况下比如按照姓氏排序,比较有用。但大多数时候,还需要使用员工的全名。下面的代码为Employee类添加一个名为FullName的公共方法,用于返回员工的全名,它由firstNameValue和lastNameValue连接得到。1 Public Function FullName()As String 2 Full
11、Name=FirstName&LastName 3 End Function下面的代码中向Employee类添加了一个计算年龄的私有方法CalcAge,并修改了只读属性Age的Get过程,以使用该私有方法。1 Private Function CalcAge(ByVal year As Integer)As Integer 2 CalcAge=My.Computer.Clock.LocalTime.Year-year 3 End Function 4 5 ReadOnly Property Age()As String 6 Get 7 Age=CalcAge(birthYearValue)8
12、End Get 9 End Property向类中添加事件时必须执行以下两个步骤。首先必须使用Event语句声明事件。然后必须使用RaiseEvent关键字引发事件,引发事件是指发出发生事件的信号。下面的代码声明了一个AgeCalculated事件。Public Event AgeCalculated(ByVal Age As Single)下面的代码在CalcAge方法中引发AgeCalculated事件。1 Private Function CalcAge(ByVal year As Integer)As Integer 2 Dim Age=My.Computer.Clock.LocalT
13、ime.Year-year 3 RaiseEvent AgeCalculated(Age)4 CalcAge=My.Computer.Clock.LocalTime.Year-year 5 End Function类的构造函数用于类的实例的创建,实现当一个类被创建时需要运行的代码。类的构造函数Sub new在类实例化的时候调用,一般用于对类中某些字段或属性进行初始化,可以类定义中的任何地方创建析构函数。下面的代码为Employee类创建了一个构造函数,用于对类内所有变量初始化。1 Sub New()2 Retired=False 3 FirstName=4 LastName=5 BirthYe
14、ar=0 6 Password=7 End Sub下面代码分别创建了使用不同参数创建类实例的构造函数。1 Sub New(ByVal first As String,ByVal last As String)2 FirstName=first 3 LastName=last 4 End Sub 5 6 Sub New(ByVal id As Integer)7 IDValue=id 8 End Sub在拥有多个构造函数的情况下,如何确定类的实例将调用哪个构造函数呢?这根据类实例化时传入的参数来确定。对象类型如下。内部对象,包括项目中的内部对象和类。外部对象,包括程序集和COM对象。New关键字
15、用于创建一个类的实例。由于对象是引用类型,所以必须显式创建之后才能使用。下面的代码声明了两个Employee类的对象。1 Dim objEm1 As Employee 2 Dim objEm2 As Employee=New Employee()对象属性的设置和获取很简单,使用对象名.属性名即可完成。例如,下面的代码为对象objEm1设置了FirstName和LastName属性。1 Dim objEm1=New Employee 2 objEm1.FirstName=Allen 3 objEm1.LastName=Smith 下面的代码则获取objEm1的年龄Age属性,并将其赋给变量a。D
16、im a As Integer=objEm1.Age使用对象名.方法()来调用对象的方法。例如,下面的代码调用了PictureBox1对象的Refresh方法,该方法用于重新绘制图片框。PictureBox1.Refresh()下面代码调用了MessageBox的Show方法,用于显示一个窗口。MessageBox.Show(This is a message box!)从上面两个例子可以看到,使用方法与使用子过程或使用函数调用一样。更具体地讲,除了需要显式指定将调用其方法的对象实例,从而对方法进行限定外,调用方法的方式与调用模块过程相同。如果方法前未指定对象名,则该实例是隐式的Me变量。首先
17、需要在创建该对象时使用WithEvents关键字。然后将该事件与某个事件处理程序相关联。可以使用Add Handler或Handles语句完成关联操作。Add Handler语句用于在运行时将事件与事件处理程序相关联。而Handles语句用于在编译时将事件与事件处理程序相关联,该语句可添加到任何与事件具有相同签名的子过程的末尾。下面的代码声明了另外一个类testClass,在该类中声明了Employee类的实例newEmployee,并编写了处理对象newEmployee的AgeCalculated事件的事件过程。1 Class testClass 2 Dim WithEvents newEm
18、ployee As New Employee 3 Private Sub newEmployee_AgeCalculated(ByVal Age As Integer)_ 4 Handles newEmployee.AgeCalculated 5 事件过程体代码 6 End Sub 7 End Class共享成员是由一个类或结构的所有实例共享的属性、过程和字段。一些编程语言将这样的项称为静态成员。VB.NET中,共享成员使用Shared关键字标识。当信息是类的一部分而非特定于类的任何实例时,共享字段和属性很有用。当更改共享字段和属性的值时,同时更改了与该类和该类的所有实例关联的值。共享方法是不
19、与类的特定实例相关联的类方法。例如,在Math类内定义的Cos方法是共享方法,可以将共享过程作为对象的方法调用或直接从类调用。共享过程和属性不具有对类的实例的访问权限,因此在共享方法中只允许对非共享数据成员进行限定引用。1 Public Class Item2 Public Shared Count As Integer=13 Public Shared Sub ShareMethod()4 MsgBox(当前Count的值为:&Count)5 End Sub6 7 Public Sub New(ByVal Name As String)8 使用Count变量的值初始化SerialNumber9 Me.SerialNumber=Count10 Me.Name=Name11 Count变量增加112 Count+=113 End Sub14 Public SerialNumber As Integer15 Public Name As String16 Public Sub InstanceMethod()17 MsgBox(该对象包含的信息为:&_18 Me.SerialNumber&vbTab&Me.Name)19 End Sub20 End Class注意,在使用共享成员时,不需要使用New关键字对类进行实例化,而是直接使用类名.共享成员名进行调用。