在类模块里写的东西就是VB的类吗??也就是那些类模块中自定义函数的总和就是一个类吗???

解决方案 »

  1.   

    基本就是这个意思通过创建类模块并赋以属性和方法,就可以定义了类,接着就可以由该类创建任意数量的对象。如何记录所创建的这些对象呢?记录对象最简单的办法,莫过于为创建的每个对象都声明一个对象变量。当然,这样对能够创建对象的数量就有了限制。可以在某个数组或者集合中保持多个对象引用,就象在本章前面的“创建对象数组”和“创建对象集合”中所讨论的那样。刚开始时,可能要定位窗体或标准模块中的对象变量、对象数组以及对象集合,就跟处理普通变量一样。但是,随着添加更多的类,可能会发现正使用的这些对象之间有明确的关系。对象模型表达了包含关系
    对象模型给出了基于对象程序的结构。通过定义程序中所使用的对象之间的关系,对象模型能够以一种使编程变得更容易的方式来组织对象。一般来说,对象模型表达了这样一个事实:即某些对象是“更大的”,或者说比其它对象更重要一些—可以认为这些对象是包含其它对象的对象,或者是由其它对象所组成的对象。例如,在编程时,可能创建一个 SmallBusiness 对象来作为程序的核心。可能想让这个 SmallBusiness 对象包含与其关联的其它类型的对象,比如 Employee 对象和 Customer 对象。可能同时也希望它包含一个 Product 对象。在图 9.11 中显示了该程序的对象模型。图 9.11   对象模型可以定义四个类模块,分别叫做 SmallBusiness、Employee、Customer 和 Product 类模块,并给它们中的每个添加合适的属性和方法,但是怎样在对象之间建立连接呢?有两种工具可以达到这个目的:即 Object 属性和 Collection 对象。下列这段代码显示了实现图 9.11 分层结构的一种办法。' SmallBusiness 类模块中声明部分的代码。
    Public Name As String
    Public Product As New Product
    Public Employees As New Collection
    Public Customers As New Collection第一次引用 Product 属性时,将创建对象,因为已经把它声明为 As New。例如,可以用下面的代码创建并设置 SmallBusiness 对象的 Product 对象的名称和价格。' 一个标准模块的代码。
    Public sbMain As New SmallBusiness
    Sub Main
       sbMain.Name = "Velociraptor Enterprises, Inc."
       ' 在代码中首次使用 Product 变量时,创建 Product 对象。
       sbMain.Product.Name = "Inflatable Velociraptor"
       sbMain.Product.Price = 1.98
       .
       .   ' 初始化并显示主窗体的代码。
       .
    End Sub注意   用公共变量来实现一个对象属性并不简洁。如果在代码中的某处,将该属性设置为 Nothing 的话,可能会无意中将 Product 对象撤消。更好的办法是创建对象属性时,将之设置为只读属性,如下列代码所示。'为更强健的对象属性所编制的代码。该属性的存储是私有的,
    '因此不能从对象的外部将之设置为 Nothing。
    Private mProduct As New ProductProperty Get Product() As Product
       '首次调用这个属性时,mProduct 包含 Nothing,
       '因此 Visual Basic 将创建一个 Product 对象。
       Set Product = mProduct
    End If一对多对象关系
    当对象之间关系是一对一时,对象属性可以正常工作。然而,经常出现的情况却是,某种类型的一个对象包含另一种类型的一些对象。在 SmallBusiness 对象模型中,Employees 属性是作为一个 Collection 对象来实现的,因此,这个 SmallBusiness 对象可以包含多个 Employee 对象。下列代码显示了怎样把新的 Employee 对象添加到这个集合中。Public Function NewEmployee(Name, Salary, HireDate, _
    ID) As Employee
       Dim empNew As New Employee
       empNew.Name = Name      '对象的隐含创建。
       empNew.Salary = Salary
       empNew.HireDate = HireDate
       '添加到集合中,并使用 ID 作为一个键。
       sbMain.Employees.Add empNew, CStr(ID)
       '返回对新 Employee 的引用。
       Set NewEmployee = empNew
    End Function在创建 SmallBusiness 对象所代表的企业雇员时,需要调用这个 NewEmployee 函数多少次,就可以调用多少次。任何时候,通过遍历 Employees 集合,都可将现有的雇员列出。注意   再次说明,并没有非常强健的实现方法。比较好的实践是创建自己的集合类,并将它们按只读属性给出。这在“创建自己的集合类”中作了讨论。提示   在 Visual Basic 的专业版和企业版中,包括 Class Builder 实用工具,利用这个实用工具,可以产生实现对象模型时需要的大量代码。Class Builder 可创建强健的对象属性和集合类,并且可以很容易地重新组织对象模型。Parent 属性
    具有对象的引用时,通过使用对象属性和对象集合,就可以到达这个引用所包含的对象。能够向分层结构的上层移动也是非常有用的,因为可以到达包含所引用对象的那个对象,。向上移动通常是用 Parent 属性来完成的。Parent 属性返回对象容器的引用。关于对象模型定位的讨论,请参阅“用部件编程”中的“定位对象模型”。可以在本章前面的“向类中添加属性”找到使用 Parent 属性的示例。提示   当把 Parent 属性赋给集合中的对象时,不要使用对 Collection 对象的引用。这个对象真正的父是包含该集合的对象。如果 Parent 属性指向了该集合,将不得不使用两级间接指针,才能到达真正的父—也就是说,要用 obj.Parent.Parent,而不是 obj.Parent。Parent 属性、循环引用,以及对象拆卸
    使用 Parent 属性的一个最大问题是它们会造成循环引用。“较大”的对象具有对所包含对象的引用,而被包含的对象通过其 Parent 属性也有引用,这样就创建了一个环,如图 9.12 所示。图 9.12   循环引用的一个例子在这幅图片上有什么错误?去除这些对象的办法,是在用对象完成工作后,释放所有对它们的引用。假设对 SmallBusiness 对象的引用是在一个名为 sbMain 的变量中,就象在本节主题前面讨论的那样,可能会写出象下面这样的代码:Set sbMain = Nothing不幸的是,仍然有一个对 SmallBusiness 对象的引用—事实上,可能有许多引用,因为每个 Employee 对象的 Parent 属性都将包含对这个 SmallBusiness 对象的引用。由于 SmallBusiness 对象的 Employees 集合包含有对每个 Employee 对象的引用,因此任何对象都不会被撤消。TearDown 方法
    一个解决这个问题的办法是,把 TearDown 方法添加给该 SmallBusiness 对象。这样,就可以将所有 SmallBusiness 对象的对象属性设置为 Nothing,同时也将所有 Collection 对象 (Employees, Customers) 设置为 Nothing。当 Collection 对象被撤消时,Visual Basic 就把它所包含的所有对象引用设置为 Nothing。如果没有对包含在 Employees 和 Customers 集合中的 Employee 和 Customer 对象其它的引用,那么它们将被撤消。当然,如果 Employee 对象是由更小的对象构成的,则将会存在其父对象所具有的同样的循环引用问题。在那种情况下,必须将一个 TearDown 方法赋给 Employee 类。要做的事情并不仅仅是将 Employees 的 Collection 对象设置为 Nothing,SmallBusiness 对象还将不得不首先遍历该集合,调用每个 Employee 对象的 TearDown 方法。其它问题
    即使这样,也并非所有对象都能被撤消。如果在程序的某个地方还有一些变量,这些变量仍然包含对 SmallBusiness 对象,或者对 SmallBusiness 对象所包含的任何对象的引用,那么这些对象将不会被破坏。程序中必须有一部分清理代码,以确保各个地方的所有对象变量都被设置为 Nothing。为了测试是否正发生这种情况,可能需要将一些调试代码添加到对象中。例如,可以将下列代码添加到标准模块中:' 全局调试集合
    Public gcolDebug As New Collection' 全局函数,赋给每个对象一个唯一的 ID。
    Public Function DebugSerial() As Long
       Static lngSerial As Long
       lngSerial = lngSerial + 1
       DebugSerial = lngSerial
    End Function在每个类模块中,都可以加入类似下面这样的代码。每个类在“Product”出现的地方提供它自己的名字。'调试 ID 的存储。
    Private mlngDebugID As LongProperty Get DebugID() As Long
       DebugID = mlngDebugID
    End PropertyPrivate Sub Class_Initialize()
       mlngDebugID = DebugSerial
       '将一个字符串登录项添加到全局集合中。
       gcolDebug.Add "Product Initialize; DebugID=" _
       & DebugID, CStr(DebugID)
    End SubPrivate Sub Class_Terminate()
       '删除字符串登录项,这样,就会知道对象不再存在了。
       gcolDebug.Remove CStr(DebugID)
    End Sub随着每个对象的创建,该对象将一个字符串放到全局集合中;当该对象撤消时,将删除该字符串。在任何时候,都可以遍历全局集合,看看什么对象还没有撤消。详细信息   用 Visual Basic 的专业版或者企业版来创建 ActiveX 部件时,对象模型承担新的重要性,并且是另一个问题集合。请参阅《部件工具指南》中,“创建 ActiveX 部件”中的“部件设计的一般准则”。