1. 繼承與封裝性(encapsulation)
1.1 公用與私有數(shù)據(jù)
前面已介紹「封藏性」(encapsulation) 之觀念。即是﹕類別內(nèi)所定義之資料成員﹐只限于程序成員才能存取之。現(xiàn)在所面臨之問題為﹕子類別能否直接存取父類別之資料呢﹖就如同﹕兒女從父母親繼承了財(cái)產(chǎn)﹐但能否取用或賣掉繼承而來的財(cái)產(chǎn)呢﹖如果可以﹐顯然違背了「封藏性」之理想。如果不行﹐顯然帶給程序員莫大之限制。理論上﹐百分之百的封藏性最為完美﹔但應(yīng)用上﹐若給予子類別若干優(yōu)待﹐能提高程序之彈性及效率。為了解決此魚與熊掌不可兼得之困境﹐vb提供三種選擇﹕
(1) public ──指定某些數(shù)據(jù)為公用的﹐任何程序皆可直接取用之﹔此時(shí)并無任何封藏作用。
(2) protected ──指定某些資料為家族公用﹐亦即只有子孫類別內(nèi)之程序可取用﹐非子孫類別之程序必須呼叫家族內(nèi)之程序代為存取。
(3) private ──指定某資料為類別私有﹐只限于該類別之程序才可取用。子類別之程序也必須呼叫父類別之程序代為存取﹐此時(shí)具百分之百封藏性。
先前介紹「封裝性」基本概念時(shí),您已經(jīng)認(rèn)識(shí)了public和private的用意了,至于protected則配合繼承來使用,于是在此特別強(qiáng)調(diào)它。
由于vb向現(xiàn)實(shí)妥協(xié)﹐開了方便之門﹐無百分之百封藏性﹔所以有些人認(rèn)為 vb并非完美的 oop語言。您認(rèn)為如何呢﹖請看個(gè)程序﹕
'ex01.bas
imports system.componentmodel
imports system.drawing
imports system.winforms
'---------------------------------------------------------
class person
private name as string
public age as integer
public sub new(byval na as string, byval a as integer)
name = na
age = a
end sub
end class
class teacher
inherits person
public salary as single
public sub new(byval na as string, byval a as integer, byval sa as single)
mybase.new(na, a)
salary = sa
end sub
public sub modifyage(byval a as integer)
age = a
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 crag as new teacher("crag", 38, 45000)
crag.modifyage(42)
messagebox.show( "age: " + str(crag.age) + ", salary: "
+ str(crag.salary))
end sub
end class
此程序輸出如下﹕
age: 42 salary: 45000
person之a(chǎn)ge資料成員定義為 public﹐表示 age為公用數(shù)據(jù)﹐任何程序皆可存取之。因之﹐teacher 之 modifyage()可使用age這名稱。相對地﹐于 teacher類別中﹐就不得使用name這名稱﹐因?yàn)閚ame定義為privatec﹐表示name為person類別之私有資料。再看teacher類別之salary資料﹐它定義為public﹐表示公用之意。所以form1_click()可直接使用 crag.salary格式取得salary之值。然而﹐不能寫成﹕crag.name ﹐因?yàn)閚ame為私有資料。例如,下述程序是不對的:
'ex02.bas
'some error here!
imports system.componentmodel
imports system.drawing
imports system.winforms
'---------------------------------------------------------
class person
private name as string
public age as integer
public sub new(byval na as string, byval a as integer)
name = na
age = a
end sub
end class
class teacher
inherits person
public salary as single
public sub new(byval na as string, byval a as integer, byval sa as single)
mybase.new(na, a)
salary = sa
end sub
public sub modifyname(byval na as string)
name = na 'error here!
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 crag as new teacher("crag", 38, 45000)
crag.modifyname("crag clinton")
messagebox.show( "age: " + str(crag.age) + ", salary: "
+ str(crag.salary))
end sub
end class
因?yàn)閚ame是person類別的私有資料,在子類別teacher的modifyname()里不能使用此資料名稱,所以錯(cuò)了。如果將person類別定義為﹕
'ex03.bas
imports system.componentmodel
imports system.drawing
imports system.winforms
'---------------------------------------------------------
class person
protected name as string
public age as integer
public sub new(byval na as string, byval a as integer)
name = na
age = a
end sub
public function getname() as string
getname = name
end function
end class
class teacher
inherits person
public salary as single
public sub new(byval na as string, byval a as integer, byval sa as single)
mybase.new(na, a)
salary = sa
end sub
public sub modifyname(byval na as string)
name = na
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 crag as new teacher("crag", 38, 45000)
crag.modifyname("crag clinton")
messagebox.show( "age: " + str(crag.age) + ", name: "
+ crag.getname())
end sub
end class
此程序輸出:
age: 42, name: crag clinton
此時(shí)﹐name為家族公用之資料﹐凡是person之子孫類別皆可取用之。但家族外之程序(如 form1_click()程序)仍不得直接使用之。如果上述定義改為﹕
class person
protected name as string
private salary as decimal
public age as integer
public sub new(byval na as string, byval a as integer)
name = na
age = a
end sub
end class
此時(shí)﹐salary為類別私有﹐其它類別不得使用。name為家族私有﹐家族外之類別不得使用。age為公用﹐任何類別皆可用。
1.2 公用與私有程序
上節(jié)介紹過﹕資料成員有 private、protected 及public之分。同樣地﹐程序成員也可分為 private、protected 及public。雖然在應(yīng)用上﹐程序成員大多定義為public﹐但必要時(shí)﹐也能將過程定義為private 或 protected。私有程序和私有資料一樣﹐只限于該類別之程序才能呼叫它。例如﹕
'ex04.bas
imports system.componentmodel
imports system.drawing
imports system.winforms
'----------------------------------------------------------------------
class person
private name as string
private age as integer
private sub modifyage(byval a as integer)
age = a
end sub
public sub new(byval na as string, byval a as integer)
name = na
age = a
end sub
public sub modify(byval na as string, byval a as integer)
name = na
modifyage(a)
end sub
public sub show()
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 p1 as new person("david", 25)
p1.show()
p1.modify("david smith", 28)
p1.show()
end sub
end class
此程序輸出:
name: david age: 25
name: david smith age: 45
modifyage()為私有程序﹐new()及modify()為公用程序。modifyage()為person類別之程序成員﹐所以modify()能呼叫modifyage()。person類別外之函數(shù)不能呼叫modifyage()。例如﹕在form1_click()中﹐可寫著 p1.modify()﹐因?yàn)閙odify()為公用程序。但于form1_click()內(nèi)﹐就不可寫著 p1.modifyage()﹐因?yàn)閙odifyage()為 private函數(shù)。如果放寬對modifyage()之限制﹐使person之子類別能呼叫modifyage()﹐就須定義modifyage()為 protected函數(shù)﹐如下﹕
'ex05.bas
imports system.componentmodel
imports system.drawing
imports system.winforms
'----------------------------------------------------------------------
class person
protected name as string
private age as integer
protected sub modifyage(byval a as integer)
age = a
end sub
public sub new(byval na as string, byval a as integer)
name = na
age = a
end sub
public sub show()
messagebox.show("name: " + name + " age: " + str(age))
end sub
end class
class teacher
inherits person
public sub new(byval na as string, byval a as integer)
mybase.new(na, a)
end sub
public sub modify(byval na as string, byval a as integer)
mybase.name = na
mybase.modifyage(a)
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 p1 as new teacher("david", 25)
p1.show()
p1.modify("kent smith", 45)
p1.show()
end sub
end class
此程序輸出:
name: david age: 25
name: kent smith age: 45
此時(shí)﹐子孫類別之函數(shù)能呼叫modifyage()﹐但家族外之類別仍不可呼叫它。總結(jié)歸納為簡單規(guī)則﹕
◎如果允許任何類別使用﹐就宣告為public。
◎如果允許子類別使用﹐就宣告為protected 。
◎如果允許本類別使用﹐就宣告為private 。
請?jiān)诳磦€(gè)例子:
'ex06.bas
imports system.componentmodel
imports system.drawing
imports system.winforms
'----------------------------------------------------------------------
class person
protected name as string
private age as integer
protected sub modifyage(byval a as integer)
age = a
end sub
public sub new(byval na as string, byval a as integer)
name = na
age = a
end sub
public sub show()
messagebox.show("name: " + name + " age: " + str(age))
end sub
end class
class teacher
inherits person
public sub new(byval na as string, byval a as integer)
mybase.new(na, a)
end sub
protected sub modify(byval na as string, byval a as integer)
mybase.name = na
mybase.modifyage(a)
end sub
end class
class fulltime_teacher
inherits teacher
public sub new(byval na as string, byval a as integer)
mybase.new(na, a)
end sub
public sub modifyvalue(byval na as string, byval a as integer)
mybase.modify(na, a)
end sub
public sub modifydata(byval na as string, byval a as integer)
mybase.name = na
mybase.modifyage(a)
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 p1 as new fulltime_teacher("david", 25)
p1.show()
p1.modifyvalue("kent smith", 45)
p1.show()
end sub
end class
此程序輸出:
name: david age: 25
name: kent smith age: 45
show()是person類別的public程序,孫子類別fulltime_teacher繼承之,成為fulltime_teacher類別的public程序,所以form1_click()程序能寫著指令:p1.show()。name和modifyage()是person的protected成員,teacher的modify()程序里能直接使用它們。而且fulltime_teacher的modifydata()程序里能直接使用它們。但是form1_click()就無法使用它們。modify()是teacher的protected成員,fulltime_teacher的modifyvalue()程序里能直接使用它們,但form1_click()就不行使用。所以若將上述form1_click()的指令改為如下,就不對了:
protected sub form1_click( ..... )
dim p1 as new fulltime_teacher("david", 25)
p1.show()
p1.modify("kent smith", 45) 'error!
p1.modifyage(24) 'error!
p1.show()
end subend class
n