870 likes | 961 Views
新觀念的 VB6 教本. 第九章 副程式與函數. 副程式與函數. 副程式( Subprogram) 與函數( Function), 是用來封裝敘述區塊的程式單元,而被封裝在副程式及函數裡的敘述區塊,並不屬於任何敘述,是個別獨立的,但這些獨立的程式單元卻可以給其他程式單元使用。 因此我們會把經常重複撰寫的敘述區塊寫成副程式或函數,以節省程式開發的時間。. 副程式 -- 封裝敘述區塊的方法 Step1. 以滑鼠雙按表單,調出程式視窗,然後拉下程式視窗的 物件盒 ,並選取其中的 "(一般)"。. 副程式 -- 封裝敘述區塊的方法 Step2.
E N D
新觀念的 VB6 教本 第九章 副程式與函數
副程式與函數 • 副程式(Subprogram)與函數(Function),是用來封裝敘述區塊的程式單元,而被封裝在副程式及函數裡的敘述區塊,並不屬於任何敘述,是個別獨立的,但這些獨立的程式單元卻可以給其他程式單元使用。 • 因此我們會把經常重複撰寫的敘述區塊寫成副程式或函數,以節省程式開發的時間。
副程式 -- 封裝敘述區塊的方法Step1 • 以滑鼠雙按表單,調出程式視窗,然後拉下程式視窗的物件盒,並選取其中的 "(一般)"。
副程式 -- 封裝敘述區塊的方法Step2 • 請在裡面輸入 “Sub MySub”,然後按 ,接著程式視窗會出現以下的變化:
封裝敘述區塊的副程式骨架(2) • 封裝敘述區塊的副程式骨架:副程式骨架是由 Sub 及 End Sub 所組成的,其作用是把敘述區塊封裝起來。 • 副程式名稱:每個副程式都要有一個名稱,這樣子其他程式單元才能夠利用這個名稱來使用這個副程式。 • 介於 Sub 及 End Sub 之間的,就是填寫敘述的地方,也就是所謂的敘述區塊
封裝敘述區塊的副程式骨架(3) • 如果我們在上述的副程式骨架裡面填寫一些敘述,就算完成一個副程式了,例如: 註:在 Print 之前加上「Debug.」可將資料輸出於即時運算視窗中。 Sub MySub() Debug.Print "*******************" Debug.Print "我的第一個副程式Debug.Print "*******************"End Sub
呼叫副程式的格式一(1) • 使用副程式的方法,是只要把副程式名稱當成一個敘述即可,如下: MySub ' 一個寫好的副程式,其角色就像 VB 的敘述一樣
呼叫副程式的格式一(2) • 百聞不如一試,把上面的副程式輸入程式視窗後,按開始命令鈕啟動程式,然後再按中斷命令鈕,使 VB 進入中斷模式,接著在即時運算視窗輸入 MySub,即可執行 MySub 副程式。
呼叫副程式的格式一(3) • 副程式雖然也可以像 VB 的敘述一樣,在即時運算視窗中執行,但是它無法在設計模式底下執行,必須先進入執行模式,然後再進入中斷模式,方可於即時運算視窗中執行副程式。
呼叫副程式的格式二(1) • 為了在閱讀上與 VB 的敘述有所區分,我們通常用另一種格式來執行副程式: • Call MySub 的作用與不含 Call 的 MySub 敘述完全相同,Call 是呼叫的意思,所以在習慣上我們通常說呼叫副程式,而不說執行副程式。 Call MySub
參數及參數傳遞的觀念(1) • 市售的掌上型電動玩具,可以分成插卡及非插卡兩大類,其中非插卡式的電動玩具,玩法只有固定一種(或幾種),一旦玩膩了,那台電動玩具就沒什麼價值了,而插卡式的電動玩具,則可以不斷換卡,達到一機多用的功能。
參數及參數傳遞的觀念(2) • 我們前面所寫的 MySub 副程式,每次執行的結果都一成不變,就像非插卡式的電動玩具一樣,價值比較低。 • 為了增加副程式的實用性,VB 讓副程式可以接受呼叫者所插入的資料。 • 在術語上,插入資料到副程式的動作叫做參數傳遞,而每一筆插入的資料則稱為參數(parameter)。
參數及參數傳遞的觀念(3) • 要讓副程式可以接受參數,在格式上要寫成: Sub 副程式名( 參數 1, 參數 2, … ) 敘述區塊End Sub
參數及參數傳遞的觀念(4) • 例如: • 在這兩個副程式裡,我們可以發現參數在副程式裡面的用法就跟變數一樣。 Sub Increment( I ) ' 含有一個參數的副程式I = I + 1 Debug.Print "I ="; IEnd SubSub Add_Three( A, B, C ) ' 含有三個參數的副程式Debug.Print A+B+CEnd Sub
呼叫含有參數的副程式 • 如何呼叫含有參數的副程式呢?首先來看個實例: • 它的意思是分別以 10、20、30替代 A、B、C 的值,相當於把 10、20、30分別指定給 A、B、C,所以將來執行到 Add_Three 副程式裡的 Debug.Print A+B+C 時,即會印出 60 的結果。 Call Add_Three( A:=10, B:=20, C:=30 )
另一種呼叫副程式的格式 • 有一種更精簡的寫法: • 意思是以 10、20、30逐一替代 Add_Three 三個參數的值,與前一種呼叫法的作用是一樣的。 Call Add_Three( 10, 20, 30 )
形式參數與實際參數(1) • 上述例子,出現在呼叫敘述中的10、20、30三個參數,叫做實際參數(actual parameter)。 • 出現在 Sub 敘述中的 A, B, C 三個參數,叫做形式參數(formal parameter)。
形式參數的意義 • 當我們定義(即撰寫)副程式時,例如前面的 Sub Add_Three( A, B, C ),由於我們並不知道將來呼叫者會傳入哪些資料作為參數,因此只好給這些參數取個暫時性的名稱。 • 如本例的 A、B、C,而將來副程式被呼叫時它們才會被真正的資料(常數值或變數)所取代,所以副程式定義中的參數都只是形式上的,故稱為「形式參數」。
實際參數的意義(1) • 而呼叫副程式時,必須以實際的資料來替代形式上的參數,使得副程式能夠拿到真正的資料來運算,這真正的資料就叫做「實際參數」,例如 Call Add_Three( 10, 20, 30 )中的10、20、30。
以變數為實際參數(1) • 呼叫時的實際參數也可以是變數,例如: • 這個呼叫敘述會以實際參數 I、J、K 替代形式參數 A、B、C,使得執行 Debug.Print A+B+C 相當於執行Debug.Print I+J+K,所以印出的結果是600。 I = 100 : J = 200 : K = 300Call Add_Three( A:=I, B:=J, C:=K ) ' 以變數I、J、K為實際參數
以變數為實際參數(2) • 雖然實際參數可以是常數值或是變數,但 VB 在替代形式參數的作法上卻有所不同。 • 如果實際參數是常數,則替代指的是替代形式參數的「值」。 • 如果實際參數是變數,則替代即是以實際參數中的變數替代形式參數。
以變數為實際參數的例子(1) • 舉個例子,假設副程式定義如下: • 而呼叫是: Sub Increment( I ) I = I + 1 Debug.Print "I ="; IEnd Sub X = 10Call Increment( I:=X ) ' 實際參數是變數Call Increment( I:=10 ) ' 實際參數是常數值
以變數為實際參數的例子(2) • 其中 Call Increment( I:=X ) 將以變數 X 替代 I,所以副程式的執行變成: • 印出結果等於 11,而 X 的值也由 10 變成 11。 X = X + 1Debug.Print "I ="; X
以變數為實際參數的例子(3) • 至於 Call Increment( I:=10 ) 則是以 10 替代 I 的值,不是替代 I 本身,所以副程式的執行還是維持: • 而由於 I 的值已經被替代成10,所以也會印出11的結果。 I = I + 1Debug.Print "I ="; I
以變數為實際參數 -- 問題思考 • 為什麼 Call Increment( I:=10 ) 的參數傳遞中,是以10替代I的「值」,而不是直接以 10 替代 I「本身」呢? • 如果是這樣,副程式的執行將會變成: 10 = 10 + 1 ' 產生錯誤Debug.Print "I ="; 10
變數的傳值呼叫(1) • 呼叫副程式還有一種格式,是在實際參數前後加上左右括弧,如下: • 雖然只是多個括弧,但呼叫後的效應卻有所不同。 Call 副程式名( (實際參數1), (實際參數2), …)
變數的傳值呼叫(2) • 以前面的 Increment 副程式為例,以下分別是實際參數前後不加 ( ) 及加 ( ) 兩種呼叫的方式及執行結果:
變數的傳值呼叫(3) • 其中 Call Increment( (X) ) 的呼叫中,(X) 表示「取變數 X 的值」,所以它相當於 Call Increment( I:=10 )。因此這兩種呼叫在副程式裡面的執行分別是: • 所以 X 才會得到兩種不同的結果。
變數的傳值呼叫意義 • 呼叫時在變數前後加上左右括弧,使替代形式參數的是實際參數的值,而不是實際參數本身的方式,叫做傳值呼叫(call by value)。
ByVal 保留字 • 如果副程式定義時,在形式參數前面加上 ByVal 保留字,也會使得呼叫方式變成傳值呼叫,例如:
ByVal 保留字的作用 • ByVal 的作用是傳值呼叫。 • 加了 ByVal 之後,將來的呼叫不管是 Call Increment( I:=X )或是Call Increment( I:=(X) ),其代表的意義都是取變數 X 的值取代參數 I 的值,所以呼叫之後 X 的值都不會改變。
形式參數的型別(1) • 定義副程式時,我們還可以宣告形式參數的型別,格式是: Sub 副程式名( 形式參數1 As 型別名, 形式參數2 As 型別, …) 敘述區塊End Sub
形式參數的型別(2) • 例如:
形式參數的型別比較例一(1) • 定義副程式時,宣告參數型別與不宣告參數型別有什麼不同呢?請比較以下實例:
形式參數的型別比較例一(2) • 執行後分別印出:8.1 及 9。這兩個副程式都可以細解成: • 但 Add_Three_Int 副程式把 A、B、C 都宣告成整數了,所以 1.6、2.7、3.8 指定給 A、B、C 時,必須轉換成整數,而變成 2、3、4,所以執行結果等於 9。 A = 1.6B = 2.7C = 3.8Debug.Print A+B+C
形式參數的型別比較例二(1) • 再比較以下實例: Call Add_Three_Int( A:="10", B:="20", C:="30" )Call Add_Three( A:="10", B:="20", C:="30" )
形式參數的型別比較例二(2) Call Add_Three_Int( A:="10", B:="20", C:="30" )Call Add_Three( A:="10", B:="20", C:="30" ) • 結果分別印出 60 及 102030 。 • 其中第一個呼叫敘述,由於形式參數 A、B、C 都宣告成整數,所以實際參數的 “10”、“20”、“30” 會被轉換成10、20、30,所以得到 60 的結果。 • 而第二個呼叫敘述,由於形式參數 A、B、C 都未宣告型別,所以實際參數 "10"、"20"、"30" 都維持原來的字串特性,而 '+' 對字串來說表示串接運算,所以得到 "102030" 的結果。
形式參數的型別 – 注意事項(1) • 若形式參數宣告了型別,而呼叫時的實際參數是變數,則實際參數與形式參數的型別必須相同才行,例如: P# = 1.6 : Q# = 2.7 : R# = 3.8Call Add_Three_Int( A:=P#, B:=Q#, C:=R# ) '錯誤!
形式參數的型別 – 注意事項(2) • 為什麼會產生錯誤呢?因為例子中的實際參數 P#、Q#、R# 都是倍精準度型別,而形式參數 A、B、C 則都是整數型別,它們不管所佔空間或資料儲存方式均不同,所以不能替代。
形式參數的型別 – 問題思考 1 • 如果把上面的呼叫修改如下,是不是就會為 VB 所接受,為什麼? Call Add_Three_Int( A:=(P#), B:=(Q#), C:=(R#) )
形式參數的型別 – 問題思考 2 如果定義 Add_Three_Int 副程式時,在參數 A、B、C 前面都加上 ByVal 保留字,變成: • 則呼叫: • 是不是就會為VB所接受,為什麼? Sub Add_Three_Int(ByVal A As Integer,ByVal B As Integer,ByVal C As Integer ) Call Add_Three_Int( A:=(P#), B:=(Q#), C:=(R#) )
形式參數的型別 – 問題說明 • 兩者都為 VB 所接受。 • 在以上兩個問題中,雖然形式參數與實際參數的型別並不相同,但由於兩者都屬於傳值呼叫,因此不受型別不同的限制。
函數 • 函數是另一種特殊形式的副程式。 • 這種副程式有的存在於 VB 的語言系統裡,稱為內建函數,我們曾經使用過的 Asc、TypeName 就是 VB 的內建函數。 • 另一種函數就像副程式一樣可以由我們自己定義的,稱為自定函數。
函數的呼叫(1) • 呼叫函數的方法與呼叫副程式十分相似: 呼叫副程式: Call 副程式名( 實際參數串列 )呼叫函數 : v = 函數名( 實際參數串列 )