请注意 ......
著作权所有人:物泽计算机事业股份有限公司、
MISOO对象技术顾问团队、对象导向杂志作者、等。
u本文件摘自 对象导向杂志、精通对象观念与技术等书籍著作。
u本文件仅供您的参阅,请遵守著作权法,不得做其它商业用途。
主题: 类别继承(Inheritance)关系
?????????? 内容 ??????????
v 1. 定类别之继承
v 2. 定义继承关系
v 3. 藉「继承」扩充程序
1. 类别之继承
类别之间﹐有些互为独立﹐有些具有密切关系。兹介绍类别间常见的关系──「父子」关系﹔由于儿女常继承父母之生理或心理特征﹐所以又称此关系为「继承」(Inheritance) 关系。类别间之密切关系﹐把相关的类别组织起来﹐并且组织程序内之对象。若程序内之对象毫无组织﹔呈现一片散沙﹐就不是好程序。完美之VB程序﹐必须重视类别间之关系﹐对象是有组织的。
如果 A类别「继承」 B类别﹐则称 A为「子类别」(Subclass)﹐也称B 为「父类别」(Superclass)﹐亦即 B为 A之父类别﹐A 为 B之子类别。在 C++中﹐父类别又称为「基础类别」(Base Class)﹐子类别又称为「衍生类别」(Derived Class) 。也许您觉得「继承」之观念很陌生﹐不知如何看出类别间之继承关系。别担心﹐有个简单方法﹕下列两叙述之意义相同──
(1) A 为 B之子类别。
(2) A 为 B之一种(A kind of) 特殊类别。
根据叙述 (2)能轻易找到父子关系。例如﹕肯尼士(Kennex)生产高品质球拍﹐球拍分两种﹕网球拍与羽球拍。从此句子得知﹕网球拍为一种(A kind of) 球拍﹐羽球拍亦为一种球拍。因之﹐网球拍为球拍之子类别﹐羽球拍亦为球拍之子类别﹐亦即球拍是父类别。以下图标之﹕
图1、 基础类别与衍生类别
如果设计程序来记录球拍之生产情形﹐则程序应定义基础类别──球拍﹐以及两衍生类别──网球拍及羽球拍。程序应藉继承关系将三类别组织起来。除了物品(如球拍、汽车等)外﹐人也有继承关系。例如﹕学校人员包括学生、老师及职员﹐老师又分为专任老师及兼任老师。学校的人事软件系统﹐应定义类别关系如下﹕
图2、 三代继承关系
程序不仅要定义类别﹐也要定义其继承关系。
2. 定义继承关系
前面各章里﹐已介绍如何定义类别﹔本节将告诉您如何定义类
别之继承关系。兹举例说明之﹕
程序的设计过程是﹕
step 1. 定义基础类别(父类别)。如﹕
Class Person
‥‥
End Class
step 2. 定义衍生类别(子类别)。如﹕
Class Teacher
Inherits Person
‥‥
End Class
Class Student
Inherits Person
‥‥
End Class
Inherits字眼之后为父类别名称。它表达了:Teacher 为Person之子类别﹐且 Student为Person之子类别。现在﹐已知道如何表达继承关系了﹔然而﹐子类别从父类别继承什么东西呢﹖类别包含「资料」及「程序」。因之﹐子类别继承父类别之资料及程序。现在﹐请看看如何继承资料及程序。下述程序定义 Person 类别﹐含有 2项资料及 3个程序﹕
'ex01.bas
Imports System.ComponentModel
Imports System.Drawing
Imports System.WinForms
'-----------------------------------------------------------------------------------------
Class Person
Private name As String
Private age As Integer
Public Sub SetValue(ByVal na As String, ByVal a As Integer)
name = na
age = a
End Sub
Public Function birthYear() As Integer
birthYear = 2001 - age
End Function
Public Sub Display()
Messagebox.Show("Name: " + name + " Age: " + str(age))
End Sub
End Class
'-----------------------------------------------------------------------------------------
Public Class Form1
Inherits System.WinForms.Form
Public Sub New()
MyBase.New()
Form1 = Me
'This call is required by the Win Form Designer.
InitializeComponent()
'TODO: Add any initialization after the InitializeComponent() call
End Sub
'Form overrides dispose to clean up the component list.
Public Overrides Sub Dispose()
MyBase.Dispose()
components.Dispose()
End Sub
#Region " Windows Form Designer generated code "
.......
#End Region
Protected Sub Form1_Click( ByVal sender As Object, ByVal
e As System.EventArgs)
Dim mike As Person
mike = New Person()
mike.SetValue("Mike", 45)
mike.Display()
Messagebox.Show("BirthYear: " + Str(mike.birthYear()))
End Sub
End Class
此程序输出如下﹕
Name: Mike Age: 45
BirthYear: 1956
所谓继承资料﹐表示继承资料成员之定义﹐而不是继承资料之值﹐请详加区别之。类别定义资料成员(含型态及名称)﹐对象诞生后﹐对象内才有资料值。所以「类别继承」乃继承类别之定义﹐不是继承对象之值。也就是说﹕若父类别定义name及 age两个资料成员﹐则子类别天生就拥有此两个资料成员﹐所以子类别不需定义它们。所谓继承程序﹐表示子类别天生就拥有父类别定义之程序成员。例如﹕Person的子类别天生就具有 SetValue()、birthYear()及Display()程序。现在﹐就来定义Person之子类别。
'ex02.bas
Imports System.ComponentModel
Imports System.Drawing
Imports System.WinForms
'-----------------------------------------------------------------------------------------
Public Class Person
Private name As String
Private age As Integer
Public Sub SetValue(ByVal na As String, ByVal a As Integer)
name = na
age = a
End Sub
Public Function birthYear() As Integer
birthYear = 2001 - age
End Function
Public Sub Display()
Messagebox.Show("Name: " + name + " Age: " + str(age))
End Sub
End Class
Public Class Teacher
Inherits Person
End Class
'-----------------------------------------------------------------------------------------
Public Class Form1
Inherits System.WinForms.Form
Public Sub New()
MyBase.New()
Form1 = Me
'This call is required by the Win Form Designer.
InitializeComponent()
'TODO: Add any initialization after the InitializeComponent() call
End Sub
'Form overrides dispose to clean up the component list.
Public Overrides Sub Dispose()
MyBase.Dispose()
components.Dispose()
End Sub
#Region " Windows Form Designer generated code "
.......
#End Region
Protected Sub Form1_Click( ByVal sender As Object, ByVal
e As System.EventArgs)
Dim steven As Teacher
steven = New Teacher()
steven.SetValue("Steven", 35)
steven.Display()
End Sub
End Class
此程序输出如下﹕
Name: Steven Age: 35
表面上Teacher 类别中﹐未定义数据项及程序﹐但事实上已拥有name及 age两个资料成员﹐也拥有 SetValue()、birthYear()及Display() 三个程序成员。因之﹐steven为Teacher类别之对象﹐它能呼叫SetValue()及Display()程序。在应用上﹐子类别通常拥有自己的数据项及程序﹐使其有别于父类别。例如﹕
'ex03.bas
Imports System.ComponentModel
Imports System.Drawing
Imports System.WinForms
'------------------------------------------------------------------------------------------------------
Public Class Person
Private name As String
Private age As Integer
Public Sub SetValue(ByVal na As String, ByVal a As Integer)
name = na
age = a
End Sub
Public Function birthYear() As Integer
birthYear = 2001 - age
End Function
Public Sub Display()
Messagebox.Show("Name: " + name + " Age: " + str(age))
End Sub
End Class
Public Class Teacher
Inherits Person
Private salary As Decimal
Public Sub tr_SetValue( ByVal na As String, ByVal a As Integer, ByVal
sa As Decimal)
SetValue(na, a)
salary = sa
End Sub
Public Sub pr()
MyBase.Display()
Messagebox.Show("Salary: " + str(salary))
End Sub
End Class
'-----------------------------------------------------------------------------------------------------
Public Class Form1
Inherits System.WinForms.Form
Public Sub New()
MyBase.New()
Form1 = Me
'This call is required by the Win Form Designer.
InitializeComponent()
'TODO: Add any initialization after the InitializeComponent() call
End Sub
'Form overrides dispose to clean up the component list.
Public Overrides Sub Dispose()
MyBase.Dispose()
components.Dispose()
End Sub
#Region " Windows Form Designer generated code "
........
#End Region
Protected Sub Form1_Click( ByVal sender As Object, ByVal
e As System.EventArgs)
Dim steven As Teacher
steven = New Teacher()
steven.tr_SetValue("Steven", 35, 35000)
steven.pr()
End Sub
End Class
此程序输出如下﹕
Name: Steven Age: 35
Salary: 35000
现在﹐Teacher 类别含有三个资料成员﹕
1. name ──从Person类别继承而来。
2. age ──从Person类别继承而来。
3. salary ──自己定义的。
此外﹐也含有五个程序成员﹕
1. SetValue() ──从Person继承而来。
2. birthYear()──从Person继承而来。
3. Display() ──从Person继承而来。
4. tr_SetValue()──自己定义的。
5. pr()──自己定义的。
由于SetValue()为 Teacher之程序成员﹐所以tr_SetValue()能直接呼叫SetValue()来设定name及age值﹔之后﹐tr_SetValue()自己设定salary之值。同理﹐pr()能直接呼叫 Display()来显示name及age之内容﹔之后﹐pr()自己输出salary之值。也许﹐您会问道﹕子类别自己定义之程序﹐是否能与父类别之程序同名称呢﹖答案是肯定的﹐而且是常见之写法。如果名称相同但是参数不一致(像参数个数不同或参数型态不同),就是父子类别之间的程序多重定义(Procedure Overloading)了,必须写上Overloads字眼。例如﹕上述程序相当于──
'ex04.bas
Imports System.ComponentModel
Imports System.Drawing
Imports System.WinForms
'------------------------------------------------------------------------------------------
Class Person
Private name As String
Private age As Integer
Public Sub New()
End Sub
Public Sub SetValue(ByVal na As String, ByVal a As Integer)
name = na
age = a
End Sub
Public Function birthDay() As Integer
birthDay = 2001 - age
End Function
Public Sub Display()
Messagebox.Show("Name: " + name + " Age: " + str(age))
End Sub
End Class
Class Teacher
Inherits Person
Private salary As Decimal
Public Overloads Sub SetValue( ByVal na As String, ByVal a As Integer, ByVal
sa As Decimal)
SetValue(na, a)
salary = sa
End Sub
Public Sub pr()
MyBase.Display()
Messagebox.Show("Salary: " + str(salary))
End Sub
End Class
'------------------------------------------------------------------------------------------
Public Class Form1
Inherits System.WinForms.Form
Public Sub New()
MyBase.New()
Form1 = Me
'This call is required by the Win Form Designer.
InitializeComponent()
'TODO: Add any initialization after the InitializeComponent() call
End Sub
'Form overrides dispose to clean up the component list.
Public Overrides Sub Dispose()
MyBase.Dispose()
components.Dispose()
End Sub
#Region " Windows Form Designer generated code "
........
#End Region
Protected Sub Form1_Click( ByVal sender As Object, ByVal
e As System.EventArgs)
Dim steven As Teacher
steven = New Teacher()
steven.SetValue("Steven", 35, 35000)
steven.pr()
End Sub
End Class
此程序输出如下﹕
NAME: Steven
AGE : 35
Salary: 35000
此种情况﹐Teacher 类别拥有两个 SetValue()程序﹐一个由Person继承而来﹐一个是自己定义的。同时﹐也拥有两个Display()程序。此时﹐计算机如何分辨它们呢﹖计算机依据程序的参数来决定呼叫那一个程序,当您写成 steven.SetValue("Steven", 35, 35000)时,此SetValue()是子类别自己的SetValue()。而写成SetValue(na,a)时,则是由Person类别继承而来之SetValue()程序。此VB程序已定义如下之类别关系﹕
接下来﹐再为Person定义一个子类别── Student。程序如下﹕
'ex05.bas
Imports System.ComponentModel
Imports System.Drawing
Imports System.WinForms
'------------------------------------------------------------------------------------------
Public Class Person
Private name As String
Private age As Integer
Public Sub New()
End Sub
Public Sub SetValue(ByVal na As String, ByVal a As Integer)
name = na
age = a
End Sub
Public Function birthDay() As Integer
birthDay = 2001 - age
End Function
Public Sub Display()
Messagebox.Show("Name: " + name + " Age: " + str(age))
End Sub
End Class
Public Class Teacher
Inherits Person
Private salary As Decimal
Public Overloads Sub SetValue( ByVal na As String, ByVal a As Integer, ByVal
sa As Decimal)
SetValue(na, a)
salary = sa
End Sub
Public Sub pr()
MyBase.Display()
Messagebox.Show("Salary: " + str(salary))
End Sub
End Class
Public Class Student
Inherits Person
Private student_number As Integer
Public Overloads Sub SetValue( ByVal na As String, ByVal a As Integer, ByVal
no As Integer)
SetValue(na, a)
student_number = no
End Sub
Public Sub pr()
MyBase.Display()
Messagebox.Show("StudNo: " + str(student_number))
End Sub
End Class
'-----------------------------------------------------------------------------------------
Public Class Form1
Inherits System.WinForms.Form
Public Sub New()
MyBase.New()
Form1 = Me
'This call is required by the Win Form Designer.
InitializeComponent()
'TODO: Add any initialization after the InitializeComponent() call
End Sub
'Form overrides dispose to clean up the component list.
Public Overrides Sub Dispose()
MyBase.Dispose()
components.Dispose()
End Sub
#Region " Windows Form Designer generated code "
........
#End Region
Protected Sub Form1_Click( ByVal sender As Object, ByVal
e As System.EventArgs)
Dim x As New Person()
x.SetValue("Alvin", 32)
Dim y As New Student()
y.SetValue("Tom", 36, 11138)
x.Display()
y.pr()
End Sub
End Class
此程序输出﹕
Name: Alvin Age: 32
Name: Tom Age: 36
StudNo: 11138
此时﹐Student 类别含有name、age 及student_number三个资料成员。而且拥有 SetValue()、Person.SetValue() 、Display()、pr() 及birthYear()五个程序成员。于是建立了如下之继承关系﹕
x 对象含name及age 两项资料﹐指令──x.SetValue ("Alvin", 32)﹐将资料存入x 对象中。因Student继承Person﹐所以y 对象内含name、age 及student_number三项资料﹐指令──y.SetValue("Tom", 36, 11138) 将资料存入y 对象中。上述 SetValue()程序之功能是﹕设定对象之初值。可由建构者(Constructor) 代替之。所以此Student之定义相当于──
'ex06.bas
Imports System.ComponentModel
Imports System.Drawing
Imports System.WinForms
'----------------------------------------------------
Public Class Person
Private name As String
Private age As Integer
Public Sub New()
End Sub
Public Sub SetValue(ByVal na As String, ByVal a As Integer)
name = na
age = a
End Sub
Public Function birthDay() As Integer
birthDay = 2001 - age
End Function
Public Sub Display()
Messagebox.Show("Name: " + name + " Age: " + str(age))
End Sub
End Class
Public Class Teacher
Inherits Person
Private salary As Decimal
Public Overloads Sub SetValue(ByVal na As String, ByVal a As Integer, ByVal sa As Decimal)
SetValue(na, a)
salary = sa
End Sub
Public Sub pr()
MyBase.Display()
Messagebox.Show("Salary: " + str(salary))
End Sub
End Class
Public Class Student
Inherits Person
Private student_number As Integer
Public Sub New(ByVal na As String, ByVal a As Integer, ByVal no As Integer)
SetValue(na, a)
student_number = no
End Sub
Public Sub pr()
MyBase.Display()
Messagebox.Show("StudNo: " + str(student_number))
End Sub
End Class
'------------------------------------------------------
Public Class Form1
Inherits System.WinForms.Form
Public Sub New()
MyBase.New()
Form1 = Me
'This call is required by the Win Form Designer.
InitializeComponent()
'TODO: Add any initialization after the InitializeComponent() call
End Sub
'Form overrides dispose to clean up the component list.
Public Overrides Sub Dispose()
MyBase.Dispose()
components.Dispose()
End Sub
#Region " Windows Form Designer generated code "
........
#End Region
Protected Sub Form1_Click( ByVal sender As Object, ByVal
e As System.EventArgs)
Dim x As New Person()
x.SetValue("Alvin", 32)
Dim y As New Student("Tom", 36, 11138)
x.Display()
y.pr()
End Sub
End Class
此程序输出﹕
Name: Alvin Age: 32
Name: Tom Age: 36
StudNo: 11138
子类别之建构者呼叫父类别之SetValue()来设定对象初值。请仔细看y 对象之诞生过程﹕y 诞生时﹐建构者──
Public Sub New(ByVal na As String, ByVal a As Integer, ByVal no As Integer)
SetValue(na, a)
student_number = no
End Sub
它先呼叫父类别的自然建构者Person.New()一起诞生y 对象。此时﹐Person.New()诞生如下﹕
继承部分是Person.New()诞生的。Person.New()任务完成了﹐轮到Student的建构者本身诞生(扩充)如下﹕
诞生完毕﹐开始执行Student建构者内之指令以设定y 之初值。首先呼叫父类别的SetValue() ﹐于是SetValue()将值存入y 如下﹕
最后﹐执行指令── student_number = no﹐设定student_number数据之初值﹕
于是﹐Student的建构者诞生y 对象﹐也设定初值﹐功成圆满。
上述的Student建构者呼叫父类别之自然建构者(因为Person类别未定义建构者﹐计算机自动产生自然建构者)来协助诞生对象。如果Person类别定义了建构者﹐Student建构者便能直接呼叫Person建构者了。例如﹕
'ex07.bas
Imports System.ComponentModel
Imports System.Drawing
Imports System.WinForms
'-----------------------------------------------------------------------------------------
Public Class Person
Private name As String
Private age As Integer
Public Sub New(ByVal na As String, ByVal a As Integer)
name = na
age = a
End Sub
Public Function birthDay() As Integer
birthDay = 2001 - age
End Function
Public Sub Display()
Messagebox.Show("Name: " + name + " Age: " + str(age))
End Sub
End Class
Public Class Teacher
Inherits Person
Private salary As Decimal
Public Sub New(ByVal na As String, ByVal a As Integer, ByVal sa As Decimal)
MyBase.New(na, a)
salary = sa
End Sub
Public Sub pr()
MyBase.Display()
Messagebox.Show("Salary: " + str(salary))
End Sub
End Class
Public Class Student
Inherits Person
Private student_number As Integer
Public Sub New(ByVal na As String, ByVal a As Integer, ByVal no As Integer)
MyBase.New(na, a)
student_number = no
End Sub
Public Sub pr()
MyBase.Display()
Messagebox.Show("StudNo: " + str(student_number))
End Sub
End Class
'-----------------------------------------------------------------------------------------
Public Class Form1
Inherits System.WinForms.Form
Public Sub New()
MyBase.New()
Form1 = Me
'This call is required by the Win Form Designer.
InitializeComponent()
'TODO: Add any initialization after the InitializeComponent() call
End Sub
'Form overrides dispose to clean up the component list.
Public Overrides Sub Dispose()
MyBase.Dispose()
components.Dispose()
End Sub
#Region " Windows Form Designer generated code "
........
#End Region
Protected Sub Form1_Click( ByVal sender As Object, ByVal
e As System.EventArgs)
Dim x As New Person("Alvin", 32)
Dim y As New Student("Tom", 36, 11138)
x.Display()
y.pr()
End Sub
End Class
此程序输出﹕
Name: Alvin Age: 32
Name: Tom Age: 36
StudNo: 11138
子类别之建构者──
Public Sub New(ByVal na As String, ByVal a As Integer, ByVal sa As Decimal)
......
End Sub
先呼叫父类别之建构者──
Public Sub New(ByVal na As String, ByVal a As Integer)
......
End Sub
协助诞生对象如下﹕
接着﹐执行父类别Person的建构者内之指令﹐设定初值如下﹕
Person建构者工作完成了﹐轮到Student建构者的工作﹐扩充对象如下﹕
诞生完毕﹐执行Student建构者内之指令﹐设定初值﹕
于是﹐y 对象诞生完毕了。
子类别建构者呼叫父类别建构者之模式﹕
例如﹐Student建构者内的MyBase.New(na, a)指令将na及a值传递给Person建构者﹐于是Person建构者设定name及age之初值。除了呼叫Person建构者之外﹐还执行自己的指令──student_number = no ﹐设定student_number之初值。Student类别之对象含有三个资料成员﹐其中name及 age是由Person类别继承而来﹐就藉Person建构者设定其初值。至于Student类别自己定义之资料成员student_number﹐就由自己的指令──student_number = no设定其初值。
3. 藉「继承」扩充程序
程序之发展是渐进的﹐软件内之类别需随企业之成长而不断扩充。类别扩充常源于﹕
(1) 企业成长了﹐产生了新类别。
例如﹕某计算机公司﹐过去制造大型及迷你计算机﹐现在新推出个人计算机。就必须建立新子类别如下﹕
图3、 程序扩充方法──衍生子类别
再如﹐某银行过去提供支票帐户(Checking Account)及储蓄帐户(Saving Account)给客户﹐现在拟增加定期帐户(CD Account)。就得新增子类别如下﹕
这新类别CD_Account继承父类别Saving_Account及Account 的资料及程序。例如﹐Account 之定义如下﹕
'ex08.bas
Imports System.ComponentModel
Imports System.Drawing
Imports System.WinForms
'-----------------------------------------------------------------------------------
Class Account
Private Shared next_number As Integer
Protected acc_no As Integer
Protected name As String
Protected balance As Decimal
Shared Sub New()
next_number = 1000
End Sub
Public Sub New(ByVal na As String)
name = na
balance = 0
acc_no = next_number
next_number = next_number + 1
End Sub
Public Sub deposit(ByVal money As Decimal)
balance = balance + money
End Sub
Public Sub withdraw(ByVal money As Decimal)
balance = balance - money
End Sub
Public Sub close()
acc_no = -1
End Sub
End Class
Class Saving_Account
Inherits Account
Private interest_rate As Double
Public Sub New(ByVal na As String, ByVal rate As Double)
MyBase.New(na)
Me.interest_rate = rate
End Sub
Public Function comp_interest() As Double
comp_interest = balance * interest_rate
End Function
Public Sub display()
Messagebox.Show("ACC_NO: " + str(MyBase.acc_no))
Messagebox.Show("余额: " + str(Me.balance) + " 利息: "
+ str(comp_interest()))
End Sub
End Class
'-----------------------------------------------------
Public Class Form1
Inherits System.WinForms.Form
Public Sub New()
MyBase.New()
Form1 = Me
'This call is required by the Win Form Designer.
InitializeComponent()
'TODO: Add any initialization after the InitializeComponent() call
End Sub
'Form overrides dispose to clean up the component list.
Public Overrides Sub Dispose()
MyBase.Dispose()
components.Dispose()
End Sub
#Region " Windows Form Designer generated code "
.......
#End Region
Protected Sub Form1_Click( ByVal sender As Object, ByVal
e As System.EventArgs)
Dim saving_acc As New Saving_Account("Tom Bush", 0.085)
Dim account As Saving_Account
account = New Saving_Account("Linda Lin", 0.008)
account.deposit(5000)
account.withdraw(2500)
account.display()
account.close()
End Sub
End Class
此程序输出﹕
ACC_NO: 1001
余额: 2500
利息: 20
因Saving_Account继承Account ﹐所以Saving_Account类别亦拥有deposit() 、withdraw()及close() 三个程序。请换个角度﹐从Saving_Account类别之设计者来看﹐他透过继承关系来「借用」父类别之程序。「借用」又称为「再使用」(Resue) ﹐能使得子类别简单但却强而有力。就如Saving_Account类别显得比Account 类别简单﹐但它总共却含有deposit() 、withdraw()等6 个程序﹐功能比Account 类别强大许多。对于指令──account.deposit(5000) 而言﹐其有两种意义﹕
I. Saving_Account继承Account ﹐所以Saving_Account具有deposit() 程序﹐可将5000存入account 对象。
II. Saving_Account为Account 之子类别﹐它能借用(再使用)父类别之deposit() 程序﹐来将5000存入account 对象。
这两者是一体的两面﹐继承功能让软件师能不断新增子类别﹐不断再使用现有类别之程序﹐来简化子类别之复杂度。继承使得子类别拥有祖父类别之各种功能﹐且再增加新功能﹔再使用使得子类别尽量委托祖父类别来担任工作﹐自己以逸待劳。因而﹐善用继承功能﹐时时心存再使用观念﹐便能设计简单却功能强大的子类别了。而程序员的效率提升了﹐软件之成本下降了﹐此乃OOP 的理想目标之一。兹再扩充一个子类别CD_Account如下﹕
'ex09.bas
Imports System.ComponentModel
Imports System.Drawing
Imports System.WinForms
'--------------------------------------------------------------------------------
Class Account
Private Shared next_number As Integer
Protected acc_no As Integer
Protected name As String
Protected balance As Decimal
Shared Sub New()
next_number = 1000
End Sub
Public Sub New(ByVal na As String)
name = na
balance = 0
acc_no = next_number
next_number = next_number + 1
End Sub
Public Sub deposit(ByVal money As Decimal)
balance = balance + money
End Sub
Public Sub withdraw(ByVal money As Decimal)
balance = balance - money
End Sub
Public Sub close()
acc_no = -1
End Sub
End Class
Class Saving_Account
Inherits Account
Private interest_rate As Double
Public Sub New(ByVal na As String, ByVal rate As Double)
MyBase.New(na)
Me.interest_rate = rate
End Sub
Public Function comp_interest() As Double
comp_interest = balance * interest_rate
End Function
Public Sub display()
Messagebox.Show("ACC_NO: " + str(MyBase.acc_no))
Messagebox.Show("余额: " + str(Me.balance) + " 利息: "
+ str(comp_interest()))
End Sub
End Class
Class CD_Account
Inherits Saving_Account
Public Sub New(ByVal na As String, ByVal rate As Double, ByRef b As Decimal)
MyBase.New( na, rate + 0.003 )
MyBase.deposit(b)
End Sub
End Class
'----------------------------------------------------------------------------------
Public Class Form1
Inherits System.WinForms.Form
Public Sub New()
MyBase.New()
Form1 = Me
'This call is required by the Win Form Designer.
InitializeComponent()
'TODO: Add any initialization after the InitializeComponent() call
End Sub
'Form overrides dispose to clean up the component list.
Public Overrides Sub Dispose()
MyBase.Dispose()
components.Dispose()
End Sub
#Region " Windows Form Designer generated code "
.......
#End Region
Protected Sub Form1_Click( ByVal sender As Object, ByVal
e As System.EventArgs)
Dim a As CD_Account
a = New CD_Account("Linda Lin", 0.008, 2500)
a.display()
a.close()
End Sub
End Class
CD_Account除了在定义自己的New()之外,皆继承Saving_Account的成员。请您仔细阅读下述程序,看看跟上一个程序有何微妙差异?
'ex10.bas
Imports System.ComponentModel
Imports System.Drawing
Imports System.WinForms
'--------------------------------------------------------------------------------
Class Account
Private Shared next_number As Integer
Protected acc_no As Integer
Protected name As String
Protected balance As Decimal
Shared Sub New()
next_number = 1000
End Sub
Public Sub New(ByVal na As String)
name = na
balance = 0
acc_no = next_number
next_number = next_number + 1
End Sub
Public Sub deposit(ByVal money As Decimal)
balance = balance + money
End Sub
Public Sub withdraw(ByVal money As Decimal)
balance = balance - money
End Sub
Public Sub close()
acc_no = -1
End Sub
End Class
Class Saving_Account
Inherits Account
Private interest_rate As Double
Public Sub New(ByVal na As String, ByVal rate As Double)
MyBase.New(na)
Me.interest_rate = rate
End Sub
Public Function comp_interest() As Double
comp_interest = balance * interest_rate
End Function
Public Sub display()
Messagebox.Show("ACC_NO: " + str(MyBase.acc_no))
Messagebox.Show("余额: " + str(Me.balance) + " 利息: "
+ str(comp_interest()))
End Sub
End Class
Class CD_Account
Private acc As Saving_Account
Public Sub New(ByVal na As String, ByVal rate As Double, ByRef b As Decimal)
acc = New Saving_Account(na, rate + 0.003)
acc.deposit(b)
End Sub
Public Function comp_interest() As Double
comp_interest = acc.comp_interest()
End Function
Public Sub display()
acc.display()
End Sub
Public Sub Close()
acc.close()
End Sub
End Class
'----------------------------------------------------------------------------------
Public Class Form1
Inherits System.WinForms.Form
Public Sub New()
MyBase.New()
Form1 = Me
'This call is required by the Win Form Designer.
InitializeComponent()
'TODO: Add any initialization after the InitializeComponent() call
End Sub
'Form overrides dispose to clean up the component list.
Public Overrides Sub Dispose()
MyBase.Dispose()
components.Dispose()
End Sub
#Region " Windows Form Designer generated code "
.......
#End Region
Protected Sub Form1_Click( ByVal sender As Object, ByVal
e As System.EventArgs)
Dim a As CD_Account
a = New CD_Account("Linda Lin", 0.008, 2500)
'a.deposit(5000) 'Error here!!
a.display()
a.close()
End Sub
End Class
(2) 环境改变了﹐必须修正旧类别。
例如﹕软件内含Sales 类别如下──
'ex11.bas
Imports System.ComponentModel
Imports System.Drawing
Imports System.WinForms
'----------------------------------------------------------------------------------
Class Sales
Protected sum As Double
Public Sub New()
sum = 0
End Sub
Public Overridable Sub input(ByVal amount As Double)
sum = sum + amount
End Sub
Public Sub display()
Messagebox.Show("The Sum Is: " + str(sum))
End Sub
End Class
'-----------------------------------------------------------------------------------
Public Class Form1
Inherits System.WinForms.Form
Public Sub New()
MyBase.New()
Form1 = Me
'This call is required by the Win Form Designer.
InitializeComponent()
'TODO: Add any initialization after the InitializeComponent() call
End Sub
'Form overrides dispose to clean up the component list.
Public Overrides Sub Dispose()
MyBase.Dispose()
components.Dispose()
End Sub
#Region " Windows Form Designer generated code "
........
#End Region
Protected Sub Form1_Click( ByVal sender As Object, ByVal
e As System.EventArgs)
Dim x As New Sales()
x.input(3000.5)
x.input(7999.5)
x.input(15000)
x.display()
End Sub
End Class
此程序输出如下﹕The Sum Is: 26000
input() 输入销售金额﹐且将金额加总起来﹐存于 sum变量中。display() 显示出总金额。随着企业之成长﹐往往对软件之功能有新的需求。例如﹕希望程序输出平均销售额。此时﹐必须更新原来的软件﹐其方法有二﹕
(I) 改写 Sales类别之定义。
此为传统软件之维护方法﹐就像一座房屋﹐已不敷使用﹐于是用推土机推掉﹐重建之。通常这种方法并不佳﹐原因是﹕旧的软件有些功能仍然可用﹐废弃重建实在可惜。若不想重建﹐只想去修改它﹐但是软件若很庞大﹐得浪费人力去了解旧软件的结构﹐弄通了之后﹐才能加以修正﹐显然不经济。进一步想﹐于修正之过程中﹐不经意而更动旧软件内仍可用之部分﹐则原来正确之功能﹐反而有遭破坏之虞﹗
(II) 藉继承关系修正 Sales类别。
亦即定义 Sales之子类别﹐来修正及扩充 Sales之功能。此时﹐并未更动Sales 类别之定义﹐所以不会破坏 Sales之功能。既然保存原有的良好功能﹐又能增加新的功能﹐岂非两全其美呢﹖此「旧干发新枝」之景象即是千年神木得以茁壮且绿意盎然之道理﹐也正是 OOP魅力的源头。现在﹐就为 Sales定义个子类别叫 Sales_new如下﹕
'ex12.bas
Imports System.ComponentModel
Imports System.Drawing
Imports System.WinForms
'------------------------------------------------------------------------------------
Class Sales
Protected sum As Double
Public Sub New()
sum = 0
End Sub
Public Overridable Sub input(ByVal amount As Double)
sum = sum + amount
End Sub
Public Sub display()
Messagebox.Show("The Sum Is: " + str(sum))
End Sub
End Class
Class Sales_new
Inherits Sales
Protected number As Integer
Public Sub New()
number = 0
End Sub
Public Overrides Sub input(ByVal amount As Double)
MyBase.input(amount)
number = number + 1
End Sub
Public Sub display_average()
Dim avg As Double
If number > 0 Then
avg = sum / number
MessageBox.Show("The Average Is : " + str(avg))
End If
End Sub
End Class
'------------------------------------------------------------------------------------
Public Class Form1
Inherits System.WinForms.Form
Public Sub New()
MyBase.New()
Form1 = Me
'This call is required by the Win Form Designer.
InitializeComponent()
'TODO: Add any initialization after the InitializeComponent() call
End Sub
'Form overrides dispose to clean up the component list.
Public Overrides Sub Dispose()
MyBase.Dispose()
components.Dispose()
End Sub
#Region " Windows Form Designer generated code "
.......
#End Region
Protected Sub Form1_Click( ByVal sender As Object, ByVal
e As System.EventArgs)
Dim x As New Sales_new()
x.input(3005.5)
x.input(5994.5)
x.input(15012.6)
x.display()
x.display_average()
End Sub
End Class
此程序输出﹕
The Sum Is: 24012.6
The Average Is: 8004.2
子类别增加了新数据项number﹐重新定义了input()﹐使新input()保存父类别内之input()功能﹐并加上number = number +1之运算。保留了父类别之display()﹐但增加了display_average()程序。依此方法﹐软件自然日益茁壮﹐且历久弥新﹗藉继承关系不断扩充乃为OOP之重要技术﹐盼您善用之。n