主題: 共享成員(shared member)
?????? 內(nèi)容 ??????
v 1. 共享資料成員
v 2. 共享程序成員
您已經(jīng)習(xí)慣像 new employee("tom", 25)這樣的指令了,看到這個指令可以想向它是:employee.new("tom", 25),于是不難想象到,原來類別也是對象!這個類別對象(class object)接到new()訊息時,就去誕生一個對象,原來類別對象就是媽媽對象(meta object)!媽媽是小孩共有的,媽媽的資料值是小孩共享的,媽媽的程序是小孩共享的。本文就介紹這種共享的資料成員和程序成員。
1. 共享資料成員
對象擁有自己的空間﹐也擁有自己的資料﹔對象之間的溝通(交換資料)方法是個重要問題。如果只想傳遞某項資料時﹐該如何呢﹖
圖1、 對象間之溝通
有數(shù)種可行方法﹐請看個例子﹕
'ex01.bas
imports system.componentmodel
imports system.drawing
imports system.winforms
'----------------------------------------------------
class employee
private emp_name as string
public salary as double
public overloads sub new(byval na as string)
emp_name = na
end sub
public overloads sub new(byval na as string, byval s as double)
emp_name = na
salary = s
end sub
public sub display()
messagebox.show("name: " + emp_name + " 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 e1 as new employee("tom")
dim e2 as new employee("lily", 20000)
e1.salary = e2.salary + 5000
e1.display()
e2.display()
end sub
end class
此程序輸出如下﹕
name:tom salary:25000
name:lily salary:20000
這宣告salary為public變量﹐讓main()能直接使用salary變量。指令:
e1.salary = e2.salary + 5000
把對象e2之salary值加上5000﹐然后存入e1之salary變量中。此程序﹐重復(fù)定義了建構(gòu)者程序── new()﹐宣告對象e1及e2時﹐就有兩種選擇﹕只輸入姓名﹐或同時輸入姓名及薪資額。請注意一項缺點﹕把salary宣告為public變量﹐讓form1_click()可使用salary變量名稱﹐直接把資料存入對象中。若其它程序也依樣畫葫蘆﹐任意把值存入salary中﹐那么salary值可能無意中遭破壞了。
如果salary資料并非機密﹐尚無所謂。如果salary含有極重要資料﹐就得謹慎小心了。就像一顆炸彈(employee類別)內(nèi)的炸藥(salary資料)可能無意中因外面因素(溫度升高等)而引起變化導(dǎo)致爆炸﹐就危險了。
圖2、類別之保護功能
因之﹐為讓對象之間互相傳遞資料而把資料成員宣告為public變量并不甚妥當(dāng)。希望能像炸彈一樣﹐只能經(jīng)由信管(程序成員)使內(nèi)部的炸藥(salary)起化學(xué)作用。于是﹐宣告salary為private變量﹐把它封藏在employee的保護之中才安全。類別(及對象)之用途和手表、燈泡、蝸牛的外殼是一樣的──保護內(nèi)部之資料﹐只限特定之管道才能存取資料。然而一旦把salary藏入employee殼中﹐上述程序就出問題了﹐如下﹕
'ex02.bas
'some error here!
imports system.componentmodel
imports system.drawing
imports system.winforms
'----------------------------------------------------
class employee
private emp_name as string
private salary as double
public overloads sub new(byval na as string)
emp_name = na
end sub
public overloads sub new(byval na as string, byval s as double)
emp_name = na
salary = s
end sub
public sub display()
messagebox.show("name: " + emp_name + " 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 e1 as new employee("tom")
dim e2 as new employee("lily", 20000)
e1.salary = e2.salary + 5000 'error !
e1.display()
e2.display()
end sub
end class
因為salary變成 private變量﹐form1_click()不能使用它﹗
為了將傳遞之過程納入類別保護之中﹐有數(shù)種方法,例如:
'ex03.bas
imports system.componentmodel
imports system.drawing
imports system.winforms
'----------------------------------------------------------------------
class employee
private shared temp as double
private emp_name as string
private salary as double
shared sub new()
temp = 0
end sub
public overloads sub new(byval na as string)
emp_name = na
end sub
public overloads sub new(byval na as string, byval s as double)
emp_name = na
salary = s
end sub
public sub addsalaryto(byval emp as employee , byval money as double)
salary = emp.salary + money
end sub
public sub display()
messagebox.show("name: " + emp_name + " 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 e1 as new employee("tom")
dim e2 as new employee("lily", 20000)
e1.addsalaryto(e2, 5000)
e1.display()
e2.display()
end sub
end class
此程序輸出如下﹕
name:tom salary:25000
name:lily salary:20000
指令── salary = emp.salary + money 已經(jīng)在employee類別的保護中,這是不錯的做法。
另一種方法是采用共享資料成員,是同一類別里各對象皆共享其值;一般資料成員的值是封裝于各對象內(nèi),別的對象是拿不到的。共享資料成員的值是在對象之外,但封裝在類別內(nèi),只要是該類別的對象皆能拿到該值。因為一般資料成員的值封裝于對象內(nèi),所以又稱為對象變量(instance variable);共享資料成員封裝于類別,所以又稱為類別變量(class variable)。上述程序可改用共享變量如下﹕
'ex04.bas
imports system.componentmodel
imports system.drawing
imports system.winforms
'----------------------------------------------------
class employee
private emp_name as string
private salary as double
private shared temp as double
public overloads sub new(byval na as string)
emp_name = na
end sub
shared sub new()
temp = 0
end sub
public overloads sub new(byval na as string, byval s as double)
emp_name = na
salary = s
end sub
public sub output()
temp = salary
end sub
public sub input()
salary = temp
end sub
public sub add_temp(byval money as double)
temp = temp + money
end sub
public sub display()
messagebox.show("name: " + emp_name + " 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 e1 as new employee("tom")
dim e2 as new employee("lily", 20000)
e2.output()
e2.add_temp(5000)
e1.input()
e1.display()
e2.display()
end sub
end class
此程序輸出如下﹕
name:tom salary:25000
name:lily salary:20000
宣告指令── private shared temp as double
說明了﹐temp是共享資料成員。茲歸納,共享資料成員與一般資料成員之區(qū)別為:
「共享資料成員是各對象公用的資料﹐
而一般資料成員是對象之私有資料。」
當(dāng)?shù)?次誕生對象時﹐共享資料成員就由shared sub new()誕生了。當(dāng)執(zhí)行到指令──
dim e1 as new employee("tom")
就誕生對象e1。但temp比e1早誕生。接下來﹐執(zhí)行指令──
employee e2( "lily", 20000 )
它誕生對象e2。此時employee類別之內(nèi)容為﹕
圖3、類別溝通方式──使用共享資料成員
其中﹐e1及e2各含有一份emp_name及salary資料。然而整個employee類別才只有一份temp資料﹐對象共同分享此temp內(nèi)之資料。employee類別里的任何對象皆可視temp為其資料成員來使用﹐但事實上只有一個temp。由于它屬于所有的對象﹐所以各對象皆可經(jīng)由程序成員存取temp資料。重要的是﹐temp已在employee類別的保護之中﹐藉由它傳遞資料就無受外界干擾之虞了。
共享資料成員除了供對象之間的溝通之用外﹐還有其重要的用途──記載類別的狀況﹐例如記錄該類別共誕生了多少對象。請看個例子﹕
'ex05.bas
imports system.componentmodel
imports system.drawing
imports system.winforms
'-----------------------------------------------------------
class employee
private emp_name as string
private salary as double
private shared counter as integer
private shared sum as double
shared sub new()
counter = 0
sum = 0
end sub
public sub new(byval na as string, byval s as double)
emp_name = na
salary = s
counter = counter + 1
sum = sum + salary
end sub
public sub display_avg()
messagebox.show("the number of employee : " + str(counter))
messagebox.show("average salary : " + str(sum / counter))
end sub
public sub display()
messagebox.show("name: " + emp_name + " 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 e1 as new employee("tom", 25000)
dim e2 as new employee("lily", 20000)
e1.display()
e2.display()
e1.display_avg()
end sub
end class
此程序輸出﹕
name: tom salary: 25000
name: lily salary: 20000
the number of employee : 2
average salary : 22500
counter 記錄類別中含有多少對象。sum 儲存各對象的salary值之總和。于此﹐必須給予 counter及 sum初值。共享變量之初值設(shè)定格式為──
shared sub new()
共享資料成員1 = 初值
共享資料成員2 = 初值
......
end sub
計算機開始執(zhí)行,誕生第1個對象時﹐各共享成員就誕生了﹐而且設(shè)定了初值。此時employee類別的內(nèi)容為﹕
對象誕生時﹐會去執(zhí)行建構(gòu)者程序──public sub new(...),先把各資料存入對象之私有成員中﹔同時也執(zhí)行指令──counter = counter + 1﹐使共享變量 counter值加上 1。此外﹐也執(zhí)行指令──sum = sum + salary ﹐把e1之salary值加到 sum里頭。此時共享變量的內(nèi)容為﹕
counter 值為 1﹐表示employee內(nèi)已誕生一個對象。接著﹐誕生個體e2﹐計算機又執(zhí)行建構(gòu)者程序──public sub new(...)。它把資料存入對象e2中﹐使 counter加上 1﹐也把e2之salary值加到 sum中。此時﹐共享變量之內(nèi)容為﹕
注意﹐e1含有 4個資料成員──emp_name、salary、counter 及sum ﹔其值分別為 "tom"、 25000、 2及 45000。同時e2含有4 個資料成員──emp_name、salary、counter 及 sum﹔其值分別為"lily"、20000 、2 及 45000。只是e1之 counter值等于e2之 counter值﹐同時e1之sum 值等于e2之 sum值。
2. 共享程序成員
剛才介紹過共享資料成員(shared data member)之觀念。共享資料成員是各對象的公用數(shù)據(jù)成員﹐但并不屬于任何對象﹐而是屬于類別的。除了資料成員之外,也有共享程序成員,它是屬于類別的﹐而并不屬于任何對象﹐其不是用來存取某對象內(nèi)的值﹐而只儲存取共享資料成員之值。任何一般程序成員皆可呼叫共享程序成員來存取共享成員之值。例如﹕
'ex06.bas
imports system.componentmodel
imports system.drawing
imports system.winforms
'----------------------------------------------------------------------
class employee
private emp_name as string
private salary as double
private shared counter as integer
private shared sum as double
shared sub new()
counter = 0
sum = 0
end sub
public sub new(byval na as string, byval s as double)
emp_name = na
salary = s
counter = counter + 1
sum = sum + salary
end sub
shared function numberofobject() as integer
numberofobject = counter
end function
shared function average() as double
average = sum / counter
end function
public sub display()
messagebox.show("name: " + emp_name + " 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 e1 as new employee("tom", 25000)
dim e2 as new employee("lily", 20000)
messagebox.show(str(e1.numberofobject()) + " objects")
messagebox.show("avgerage: " + str(e2.average()))
dim e3 as new employee("linda", 15000)
messagebox.show(str(e3.numberofobject()) + " objects")
messagebox.show("average: " + str(e3.average()))
end sub
end class
此程序輸出:
2 objects
average: 22500
3 objects
average: 20000
還記得嗎﹖一般程序成員是用來處理對象內(nèi)的資料﹐所以呼叫一般程序成員之格式為──
對象. 一般程序成員
呼叫這程序成員的目的是來處理此對象之內(nèi)容。共享程序成員之目的并非在于處理對象之內(nèi)容﹐而是存取共享資料成員之值或處理些有關(guān)于整個類別的事情。因之﹐呼叫共享程序成員的格式為──
類別 . 共享程序成員
呼叫這共享程序成員之目的是來處理此類別之資料或有關(guān)之事情。
一種格式──
對象 . 共享程序成員
每個對象皆來自某個類別﹐vb看到對象名稱時﹐可對應(yīng)到它的類別﹐所
以vb在編譯這種格式時﹐會將之轉(zhuǎn)換成為﹕
類別 . 共享程序成員
亦即﹐指令── c1.nameofobject()
及 c2.nameofobject()
皆會轉(zhuǎn)換成為-- employee.nameofobject()
同理﹐e1.average()也就相當(dāng)于employee.average() 了。
由上述可知共享程序成員并非處理某個特定的對象值﹐所以沒有必要去呼叫一般的程序成員。vb也就禁止共享程序成員呼叫一般的程序成員。不過﹐反之一般程序成員卻可以呼叫共享程序成員﹐以便必要時可藉由共享程序成員來取得有關(guān)于整個類別的資料。例如:
'ex07.bas
imports system.componentmodel
imports system.drawing
imports system.winforms
'------------------------------------------------------------------------------
class employee
private emp_name as string
private salary as double
private shared counter as integer
private shared sum as double
shared sub new()
counter = 0
sum = 0
end sub
public sub new(byval na as string, byval s as double)
emp_name = na
salary = s
counter = counter + 1
me.sum = employee.sum + salary
end sub
public function getsalary() as double
getsalary = salary
end function
shared function numberofobject() as integer
numberofobject = counter
end function
shared function average() as double
dim k as double
average = employee.sum / employee.counter
' salary = salary + 2000 ' error!
' k = getsalary() ' error!
end function
public sub disp()
messagebox.show(str(employee.numberofobject()) + " objects")
messagebox.show("avgerage: " + str(employee.average()))
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 e1 as new employee("tom", 25000)
dim e2 as new employee("lily", 20000)
e2.disp()
dim e3 as new employee("linda", 15000)
e3.disp()
end sub
end class
此程序輸出:
2 objects
average: 22500
3 objects
average: 20000
共享程序,上述disp()是一般程序成員,此程序內(nèi)的指令:
public sub disp()
messagebox.show(str(employee.numberofobject()) + " objects")
......
end sub
這就呼叫了共享的numberofobject()程序。
共享程序不可呼叫一般程序,上述average()是共享程序,它不能呼叫一般程序,所以average()內(nèi)的指令有錯:
shared function average() as double
dim k as double
average = employee.sum / employee.counter
' salary = salary + 2000 ' error!
' k = getsalary() ' error!
end function
請記得,共享程序是類別對象(媽媽)的程序,媽媽與小孩各有隱私(封裝),小孩呼叫媽媽程序(即共享程序)的格式為:
媽媽 . 共享程序()
例如:employee.average()
或 對象 . 共享程序()
例如: e1.average() 或 me.average()。
但媽媽呼叫小孩程序的格式為:
對象 . 一般程序()
例如: e1.average()。
因為媽媽程序里沒有me參考變量,所以上述的 k = getsalary()指令相當(dāng)于k = me.getsalary(),就錯掉了。請再看一個例子:
'ex08.bas
imports system.componentmodel
imports system.drawing
imports system.winforms
'--------------------------------------------------------------------------------
class employee
private emp_name as string
private salary as double
private shared counter as integer
private shared p(10) as employee
shared sub new()
counter = 0
end sub
public sub new(byval na as string, byval s as double)
emp_name = na
salary = s
p(counter) = me
counter = counter + 1
end sub
shared function getobject(byval index as integer) as employee
dim sp as employee
if index > counter or index < 0 then
sp = nothing
else
sp = p(index)
end if
getobject = sp
end function
public sub display()
messagebox.show("name: " + emp_name + " salary: " + str(salary))
end sub
shared sub disp(byval e as employee)
e.display()
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 e1 as new employee("tom", 25000)
dim e2 as new employee("lily", 20000)
dim e3 as new employee("linda", 15000)
dim e4 as new employee("alvin", 5000)
dim emp as employee
emp = employee.getobject(2)
employee.disp( emp )
emp = employee.getobject(1)
employee.disp( emp )
end sub
end class
此程序輸出:
name: linda salary: 15000
name: lily salary: 20000
在媽媽對象里有一個p(10)數(shù)組,每次誕生對象時,就將新對象的參考值存入數(shù)組里。媽媽程序getobject(i)則從數(shù)組中取出第i個對象,并傳回來。媽媽程序使用格式:
對象 . 一般程序()
呼叫小孩的display()程序。
上述程序相當(dāng)于:
'ex09.bas
imports system.componentmodel
imports system.drawing
imports system.winforms
'--------------------------------------------------------------------------------
class employee
private emp_name as string
private salary as double
private shared counter as integer
private shared p(10) as employee
private shared current as employee
shared sub new()
counter = 0
end sub
public sub new(byval na as string, byval s as double)
emp_name = na
salary = s
p(counter) = me
counter = counter + 1
end sub
shared sub findobject(byval index as integer)
dim sp as employee
if index > counter or index < 0 then
sp = nothing
else
sp = p(index)
end if
current = sp
end sub
shared sub disp()
messagebox.show( "name: " + current.emp_name +
" salary: " + str(current.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 e1 as new employee("tom", 25000)
dim e2 as new employee("lily", 20000)
dim e3 as new employee("linda", 15000)
dim e4 as new employee("alvin", 5000)
employee.findobject(2)
employee.disp()
employee.findobject(1)
employee.disp()
end sub
end class
此程序輸出:
name: linda salary: 15000
name: lily salary: 20000
媽媽程序findobject(i)則從數(shù)組中找到第i個對象,并記錄在current變量里,不傳回來。n
,歡迎訪問網(wǎng)頁設(shè)計愛好者web開發(fā)。