visual basic.net 現今是一個完整的物件導向(object orient)語言,也就是完整支援封裝、繼承、多型等等程式撰寫的方式,並提供建構/解構子。所以它增加了以往 visual basic 在這一方面所缺乏的功能,如繼承。
visual basic.net 增加的繼承讓你可以其他的 class 為基礎來建立新的 class,衍生的(derived) class 可以繼承(inherit)和延伸原始 class 的屬性和方法。雖然衍生的 class 只能繼承自單一的基礎(base) class,但它可以實做(implement)無限數目的介面(interface)。衍生的 class 也可以撰寫新的方法 override 繼承下來的方法,所有 visual basic.net 建立的 class 預設都是可以被繼承的。
繼承和介面讓你可以實做多型(polymorphism),讓不同的 class 可以重新定義相同名稱的屬性和方法。多型是物件導向(object-orient)程式設計的基礎,因為它讓你可以呼叫相同名稱的方法,而不管在使用的當下是哪一種型態的物件。例如給一個 normalpayroll 的基礎 class,多型讓程式設計師可以定義多個衍生 class 不同的 payemployee 方法。其他的屬性和方法可以相同的方式使用衍生物件的 payemployee 方法,而不管是用到哪一個衍生的物件。
visual basic.net 提供下列的語句來定義和支援繼承
inherits 語句 — 定義當下 class 要繼承的 class(也稱為基礎 class)。通常可以透過屬性視窗(properties window)來設定。
notinheritable 定義子 — 防止使用者將該 class 當作基礎 class 來使用
mustinherit 定義子 — 定義該 class 不能用來建立 instance,唯一使用它的方式是繼承它。
衍生的 class 可以新的實做方式 override 一些繼承來的方法。visual basic.net 使用下列的定義子來控制方法和屬性的 overriding
overridable — 讓屬性和方法在繼承的 class 可以 override
overrides — 定義要 override 哪一個基礎的屬性或方法
notoverridable(預設) — 防止屬性或方法被繼承的 class override
mustoverride — 要求繼承的 class 一定要 override 該屬性或方法
程式碼範例如下
imports system
namespace mynamespace
class payroll overridable function payemployee(byval hoursworked as single, byval payrate as single) payemployee = hoursworked * payrate end function
end class
class bonuspayroll inherits payroll overrides function payemployee(byval hoursworked as single, byval payrate as single) payemployee = (hoursworked * payrate) * 1.45 45% 紅利 end function
end class
module mymodule sub main() dim bonuspayrollitem as bonuspayroll = new bonuspayroll dim payrollitem as payroll = new payroll dim payrate as single = 14.75 dim hoursworked as single = 40
console.writeline("normal pay is: " & pay(payrollitem, hoursworked, payrate)) console.writeline("pay with bonus is: " & pay(bonuspayrollitem, hoursworked, payrate))
end sub
function pay(byval payobject as payroll, byval hoursworked as single, byval payrate as single) pay = payobject.payemployee(hoursworked, payrate) * 0.75 withold tax end function end module
end namespace
protected sub button1_click(byval sender as system.object, byval e as system.eventargs) dim t as new thread(addressof addval) t.start()
end sub
sub addval() synclock iary dim i as integer for i = 1 to 1000000 ival += 1 next textbox1.text = cstr(ival) end synclock
end sub
建構子(constructor)和解構子(destructor)
建構子是用來控制 class 在建立一個新的 instance 時所需要做的初始化程序。同樣地,解構子是當 class 的 instance 結束時(可能是設定變數為 nothing)所需要做的程序,如釋放系統資源等等。 在原有的 vb 中,可以利用 class_initialize() 和 class_terminate() 事件程序(event procedure)來初始化或在 instance 結束時執行。
在 visual basic.net 中改以 sub new() 和 sub destruct() 程序來做建構子與解構子的動作。
sub new() 方法只會在 class 建立時執行一次,且除了以同一 class 其他的建構子或是衍生 class 的建構子的第一行程式碼呼叫之外,不可以在任何其他地方呼叫使用。且 sub new() 方法之內的程式碼在執行時,沒有任何該 class 內的成員已經被建立出來。 .net 執行環境會在清掉物件時自動呼叫它的 sub destruct() 方法,這一個副函數也不可以被呼叫使用。
.net 執行環境在系統決定該物件不需要存在時﹔會自動清掉該物件。與 class_terminate 和 sub new() 不同的是,你無法確切地知道 .net 執行環境會何時呼叫 sub destruct(),只能確定的是對該物件最後的一個參照(reference)被釋放後,系統會自動呼叫 sub destruct()。
■ 使用 sub new() 來建立參數化的建構子 —
要建立一個 class 的建構子可以在 class 定義範圍內的任何地方撰寫 sub new() 副函數。建構子的第一行程式碼必須是呼叫基礎 class 的建構子或是同一 class 內其他的建構子,這保證被繼承的物件會在衍生的物件之前初始化完成。甚至是當你在建立你自己的基礎 class 時,也通常會呼叫 mybase.new 來初始化更基礎的物件,因為所有的 class 最終都是繼承自 object class。
在呼叫完父物件的建構子後,在 sub new() 副函數內加上初始化該物件所需要的動作。sub new() 副函數可以接受參數,如下列的程式碼範例。
■ 使用 sub destruct() 當解構子 —
要建立 class 的解構子,可以在 class 的定義範圍內任何地方加上 sub destruct() 副函數。你可以在該副函數內加上釋放物件,關閉檔案等等工作。
程式碼範例如下
imports system
namespace mynamespace
module mymodule class truck private iwheels as integer sub new(iinitialwheels as integer) mybase.new 呼叫基礎 class 的建構子 iwheels=iinitialwheels end sub sub destruct() 執行一些需要的動作 end sub property wheels as integer get wheels=iwheels end get set iwheels = value end set end property end class
sub main() dim t as truck = new truck(18) console.writeline("這是一部 {0} 輪大卡車",t.wheels) console.write("請輸入您想要改裝的輪數: ") t.wheels = cint(console.readline()) console.writeline("你已經把它改裝成 " & t.wheels & " 輪大卡車") end sub
end module
end namespace
執行結果如下
delegate
delegates 的行為像一個 type-safe,物件導向式函數指標(object-oriented function pointer)。利用 delegate 傳遞用 vb 的 addressof 運算子取得 class 副函數的指標給其他的 vb class 副函數。通常會利用 delegate 來做事件處理函數,也就是當事件發生時要自動執行的函數。
每一個 delegate class 定義一個建構子,使用時會傳入一個物件方法的指標當作是參數。參數的格式如下
addressof [.]<方法名稱>
在編譯時期, 必須是一個 class 或是一個介面(interface),並且有著一個符合 delegate class 所宣告的方法格式的方法。
這個方法可以是共享的(class)方法或是 instance 方法。 要觸發 delegate class 的 instance 內的方法必須要呼叫內建的 invoke 方法,整個程式碼範例如下
imports system
namespace testdelegate public delegate sub eventhandler(byval strtext as string)
class eventtake sub getevent(byval strin as string) console.writeline("delegate 事件 " & strin) end sub
end class
class eventraise sub useinvoke() dim c as new eventtake() dim delsub as eventhandler delsub = new eventhandler(addressof c.getevent) delsub.invoke("一些狀況") end sub
end class
module module1
shared sub main() dim c2 as new eventraise() c2.useinvoke() end sub