跳转到内容

Visual Basic/面向对象编程

来自 Wikibooks,开放世界中的开放书籍

我们现在将进入 VB 的一个更高级的方面 - OOP。 但不用担心,面向对象编程非常简单,事实上,对于从未编程过的人来说,它可能比那些有很长时间传统 Fortran/Basic/Pascal(选择你最喜欢的命令式语言)编程经验的人更容易。


你现在应该熟悉 VB 的事件驱动编程风格。 但是我会再解释一下。 当你进行一般的 VB 编程时,你的思路应该遵循这种模式:“如果用户执行此操作,应该发生什么? 我该如何实现?” 然后你会编写程序以适应这些问题的答案。 这就是事件驱动编程。 你根据用户触发的事件进行编程。 拖动图片、单击按钮和输入文字都是事件。

你,作为一名勇敢的编码员,会问:“为什么我必须这样思考??”

好吧,这里有一个供你思考的替代方法:面向对象编程 (OOP)。 在 OOP 世界中,你将问题分解成小部分并分别解决。 如果你要以面向对象的方式编程,你会将每个变量或函数视为对象的属性,对你来说,一切看起来都像对象。 OOP 很难解释,所以你必须在以下示例中体验它。

想象你有一瓶果汁。 它有哪些属性? 它有哪些事件?(它能做什么?) 以下是我能想到的清单

  Private Colour As String  'What colour?
  Private Fruit As String   'What kind of fruit?
  Private Volume As Single  'How much?
  Public Sub MakeJuice(c As String, f As String, v As Single)  'Make some
    Colour = c
    Fruit = f
    Volume = v
  End Sub
  
  Public Sub Evaporate()   'Well, that's the only thing I could think of
    Volume = Volume - 10
  End Sub

看。 这就是我们的第一个类。 现在不用担心任何事情。 我会在后面详细介绍这些。 无论如何,让我们假设这个类名为“Juice”。 将其视为一瓶果汁的通用描述。 现在我们可以创建一个真正的苹果汁瓶

  Private AppleJuice As Juice  'Define
  Set AppleJuice = New Juice   'Create a new instance of Juice
  AppleJuice.MakeJuice "brown", "apple", 30

观察

  AppleJuice.Evaporate   '20 units left
  AppleJuice.Evaporate   '10 left
  AppleJuice.Evaporate   'Yes!!

“等等”,你又一次打断了我的长篇大论,“但我为什么要使用 OOP? 仅仅因为你讨厌苹果汁?”

OOP 适用于大型编程 - 随着代码的增长,程序将拥有越来越多的过程/函数,你的代码将变得非常混乱,多看一眼,你就会尖叫。 这就是我教你的 OOP 的原因!(所以,与其查看数百个分散的过程/函数,不如查看有组织的对象。)

你可以将类型视为一种简单的类形式。 类型只能保存变量,不能保存过程/函数。

在 'VB6' 中,用户定义类型 ('UDT') 和 '类' 之间的一个重要区别是 'UDT' 是值类型,而 '类' 是引用类型。 这意味着当你将一个对象('类' 的 '实例')存储在变量中时,实际发生的是存储指向现有对象的指针,但当你将 'UDT' 实例存储在变量中时,存储的是实例的副本。 例如,假设你定义了一个类 'Class1' 和一个 UDT 'Type1'

  Dim ac As Class1
  Dim bc As Class1 
  Dim at As Type1
  Dim bt As Type1

现在将 ac 赋值给 bc

Set bc = ac

并将 at 赋值给 bt

bt = at

现在对 bc 的某个属性进行更改,并查看 ac 中的相应属性。 你应该会看到,当你更改 bc 时,ac 也会更改。 这是因为 ac 和 bc 实际上是指向同一内存块的指针。 如果你对 bt 和 at 进行相同的操作,你应该会看到更改 bt 的属性不会影响 at。 这是因为 at 和 bt 是值而不是引用,并且在内存中占据不同的位置。

这在将对象存储在 '集合' 中时非常重要。 如果你将对象添加到集合中,你可以在以后更改其属性的值,集合中的对象也会发生更改。 事实上,它是一个相同的对象,因为存储在集合中的是对象的引用('指针')。 但是,如果你将 'UDT' 存储在集合中,存储的是副本,而不是引用,因此更改原始 UDT 不会影响集合的内容。

类是子例程和类型的组合。 我的意思是,当你编写类时,它看起来很像一个类型,但它也包含子例程和函数。

VB6 中的每个类都是一个独立的文件,一个文件中只能有一个类,并且该类不能分散在多个文件中; 这是 VB6 的一项功能,而不是面向对象编程的要求。

类看起来很像一个普通的模块,但文件扩展名为 .cls 而不是 .bas

继承有两种类型:实现和接口。 但是,Visual Basic Classic 仅提供接口继承。 实现继承可以通过接口继承和委托的组合来模拟。

介绍继承的一种常见方法是展示一个创建狗和猫对象或汽车和火车对象的程序。

例如,在 Visual Basic 中,我们可以像这样声明两个类狗和猫

Class cDog

[编辑 | 编辑源代码]
  Option Explicit
  
  Public Sub Sound()
    Debug.Print "Woof"
  End Sub

Class cCat

[编辑 | 编辑源代码]
  Option Explicit
  
  Public Sub Sound()
    Debug.Print "Meow"
  End Sub

模块 main

[编辑 | 编辑源代码]
  Public Sub main()
    Dim oDog as cDog
    Dim oCat as cCat
  
    Set oDog = New cDog
    Set oCat = New cCat
  
    oDog.Sound
    oCat.Sound
  
  End Sub

当你运行此程序时,它将打印

 Woof
 Meow

现在这一切都很好,直到你决定想要一个宠物数组

Dim aPets(1 to 10) as ????

除非你将 aPets 数组声明为 variant,否则你必须为它指定一个类型。 一种方法是创建一个名为 cPet 的类,并使用它代替 cDog 和 cCat

Class cPet

[编辑 | 编辑源代码]
  Option Explicit
  
  Public IsDog as Boolean
  
  Public Sub Sound()
    If IsDog Then
      Debug.Print "Woof"
    Else
      Debug.Print "Meow"
    End If
  
  End Sub

现在我们的 main 例程可能看起来像这样

  Option Explicit
  
  Dim aPet(1 to 10) as cPet
  
  Public Sub main()
  
    Dim lPet as Long
    For lPet = 1 to 10
      Set aPet(lPet) = New cPet
      If lPet<=5 then
        aPet(lPet).IsDog = True
      Else
        aPet(lPet).IsDog = False
      End If
    Next lPet    
 
    ' Now find out what noise they make.
    For lPet = 1 to 10
      aPet(lPet).Sound
    Next lPet
  
  End Sub

这应该打印

 Woof
 Woof
 Woof
 Woof
 Woof
 Meow
 Meow
 Meow
 Meow
 Meow

看起来合理吗? 就目前所揭示的要求而言,这可以正常工作。 但是,当你发现猫会做一些狗不会做的事情时会发生什么? 其他类型的宠物怎么样? 例如,你希望你的猫发出呼噜声。 你可以有一个名为 purr 的方法,但你该把它放在哪里? 它肯定不属于 cPet,因为狗不会发出呼噜声,豚鼠和鱼也不会。

要做的事情是将所有宠物共有的那些特性分离出来,并创建一个只处理这些特性的类,我们可以为此目的重写cPet。 现在,我们可以回到我们最初的 cDogcCat 类,并修改它们以从 cPet 继承接口

Class cPet 重写

[编辑 | 编辑源代码]
  Option Explicit
  
  Public Sub Sound()
  End Sub

请注意,Sound方法是空的。这是因为它的存在只是为了定义接口。接口就像插头或插座上的引脚布局;任何具有相同布局、大小和形状的插头都可以插入实现相同接口的插座。您插入的东西内部发生了什么是一个单独的问题;吸尘器和电视机都使用相同的电源插头。

为了使这工作,我们现在必须修改 cDog 和 cCat。

Class cDog

[编辑 | 编辑源代码]
  Option Explicit
  Implements cPet
  
  Private Sub cPet_Sound()
    Debug.Print "Woof"
  End Sub

Class cCat

[编辑 | 编辑源代码]
  Option Explicit
  Implements cPet
  Private Sub cPet_Sound()
    Debug.Print "Meow"
  End Sub
  
  Public Sub Purr()
    Debug.Print "Purr"
  End Sub

在上面的宠物示例中,cPet 对象的数组用于保存宠物。如果您确切知道有多少宠物,这很有效。但是,如果您收养了另一只流浪的小狗,或者您的猫生下了小猫,会发生什么情况呢?

一种解决方案是使用 Collection 对象而不是数组。Collection 对象看起来有点像数组,但它允许您添加和删除项目,而不必担心已声明的大小,它会自动扩展和收缩。

迭代器

[编辑 | 编辑源代码]


上一页:External_Processes 目录 下一页:Effective Programming
华夏公益教科书