繼承概述
面向對象編程 (OOP) 語言的一個主要功能就是繼承繼承是指這樣一種能力它可以使用現有類的所有功能並在無需重新編寫原來的類的情況下對這些功能進行擴展在 Microsoft® Visual Basic® NET 發布之前Visual Basic 程序員並不具備這種能力在 Visual Basic NET 中您可以繼承 Microsoft NET 框架中的類也可以繼承您自己創建的類在本文中我們將學習如何使用繼承並了解繼承是如何大大縮短編程時間的
簡單示例
在您創建的許多類中您會發現您常常需要與先前創建的類中的屬性和方法相同的屬性和方法例如如果有一個名為 Person 類的基類該類包含 LastName 和 FirstName 屬性以及 Print 方法您會發現對於 Employee 類您也需要這些屬性和方法您可能還需要其他屬性例如 EmployeeID 和 Salary如果從 Person 類(基類)繼承您可以將這些屬性添加到新的 Employee 類中並且仍然可以訪問 Person 類中的所有屬性繼承是指某個類可將其自身定義為具有某個特定類的所有屬性和方法然後再通過添加其他屬性和方法對基類的定義進行擴展的能力
繼承術語
在深入研究這個主題之前讓我們先來定義幾個術語通過繼承創建的新類稱為子類被繼承的類稱為基類父類或超類在某些 OOP 語言中一個子類可以繼承多個基類也就是說如果有一個 Person 類和一個 Car 類則 Driver 類可以繼承這兩個類的所有屬性和方法而在 NET 中只允許單一繼承因此每個子類只能有一個基類
NET 支持三類繼承實現繼承接口繼承和可視繼承實現繼承是指使用基類的屬性和方法而無需額外編碼的能力接口繼承是指僅使用屬性和方法的名稱但是子類必須提供實現的能力可視繼承是指子窗體(類)使用基窗體(類)的外觀和實現代碼的能力 在 NET 中一個類可以從某個基類繼承而來而這個基類又可以從另外一個類繼承而來而且您可以在一個類中使用一個或多個接口
使用繼承的原因
繼承可以避免重復編寫相同的代碼因此十分有用如果有兩個單獨的類而每個類都必須實現 FirstName 和 LastName 屬性則可能會出現重復代碼如果要更改某個屬性的實現方式則需要查找已實現這些屬性的所有類以進行更改這不僅要耗費大量時間還增加了不同類中出現錯誤的風險
在考慮使用繼承時有一點需要注意那就是兩個類之間的關系應該是屬於關系例如Employee 是一個人Manager 也是一個人因此這兩個類都可以繼承 Person 類但是 Leg 類卻不能繼承 Person 類因為腿並不是一個人
覆蓋
從基類中繼承功能時您可能會發現在基類中編寫的一般方法僅執行繼承類所需的部分功能要執行所需的全部功能您可以在新類中覆蓋基類的方法而無需使用新的名稱創建一個全新的方法
進行覆蓋時您可以選擇完全覆蓋基類的方法也可以在繼承類中編寫代碼來執行某些操作然後再調用基類的方法在覆蓋時請務必仍然使用與原始方法相同的合約(參數和返回類型)也可以選擇先調用基類的方法然後在執行完基類的方法後編寫其他代碼
繼承基類
繼承使您可以在一個類中使用另一個類的全部屬性和方法您可以使用關鍵字 Inherits 來獲得基類的功能而無需將代碼從一個類復制並粘貼到另一個類中
實現繼承
本文將創建一個新類 LineDelim它將繼承 Creating Classes in NET(英文)一文中創建的 Line 類的所有功能之後本文將通過添加兩個其他屬性和一個方法對 Line 類進行擴展要添加的第一個屬性是 Delimiter使用它可以獲得一個分隔符字符並將其設置到類中此分隔符將用於將行中的所有空格替換為分隔符字符要添加的第二個屬性是 OriginalLine它將用於在向文本行插入新的分隔符之前保留文本的原始行要創建的新方法是 ReplaceAll()它將用於將文本行中的所有空格替換為分隔符字符然後我們將學習如何覆蓋 GetWord 方法以便使用此分隔符(而不是空格)分隔文本行並搜索第一個詞
構建示例窗體
要創建窗體請單擊 Project(項目)然後單擊 Add Windows Form(添加 Windows 窗體)
將窗體命名為 frmLineTestVB 並單擊 OK(確定)
然後在該窗體上創建相應的控件並設置屬性
構建 Line 類
接下來將構建要繼承的 Line 類
從菜單中單擊 Project(項目)然後單擊 Add Class(添加類)
鍵入如下所示的代碼
Public Class Line
Private mstrLine As String
Property Line() As String
Get
Return mstrLine
End Get
Set(ByVal Value As String)
mstrLine = Value
End Set
End Property
ReadOnly Property Length() As Integer
Get
Return mstrLineLength
End Get
End Property
Public Function GetWord() As String
Dim astrWords() As String
astrWords = mstrLineSplit( ToCharArray())
Return astrWords()
End Function
End Class
創建子類
既然窗體和基類都已經創建完畢現在便可以開始執行繼承了
單擊 Project(項目)然後單擊 Add Class(添加類)將該類命名為 LineDelimvb 並單擊 OK(確定)
添加新類時請修改 Visual 所創建的代碼使之與下面的示例代碼相似
Public Class LineDelim
Inherits Line
End Class
因為添加了 Inherits Line 語句所以您可以在這一新創建的類中使用 Line 類的所有屬性和方法
試一試
打開 frmLineTestvb 窗體
雙擊 Get Word(取詞)按鈕
向此按鈕的單擊事件過程添加以下代碼
Protected Sub btnFirst_Click(ByVal sender As Object _
ByVal e As SystemEventArgs) Handles btnFirstClick
Dim oLine As LineDelim = New LineDelim()
oLineLine = txtLineText
txtFirstWordText = oLineGetWord()
End Sub
運行項目並在窗體上單擊 Get Word(取詞)按鈕您將看到The一字出現在按鈕旁邊的只讀文本框中
Inherits 語句的功能非常強大只需要使用這一個語句就可以在 LineDelim 類中使用 Line 類的所有屬性和方法盡管這個新類尚未執行任何新的操作但它卻表明從 Line 類中繼承的所有代碼都可以正常工作
添加其他功能
現在您可以使用其他屬性和方法對 LineDelim 類進行擴展要向 LineDelim 類添加兩個新的屬性請執行以下步驟
在上一部分添加的 Inherits 語句後添加兩個 Private 變量如下所示
Private mstrDelim As String =
Private mstrOriginal As String
鍵入如下代碼為這兩個 Private 變量添加適當的 Property 語句您可以將以下代碼放在上面輸入的兩行代碼後面(緊挨這兩行)
Public Property Delimiter() As String
Get
Return mstrDelim
End Get
Set(ByVal Value As String)
mstrDelim = Value
End Set
End Property
Public ReadOnly Property OriginalLine() As String
Get
Return mstrOriginal
End Get
End Property
現在您可以使用 Delimiter 屬性設置並獲取 Private 變量 mstrDelim 的值
如果不希望其他人更改這些屬性您可以將屬性設為只讀要執行此操作請不再使用 Set 語句並在 Property 語句中添加 ReadOnly 屬性有關示例請參見上面代碼中顯示的 OriginalLine 屬性聲明
接下來需要創建一個稱為 ReplaceAll 的方法此方法可以將文本行中的所有空格替換為傳遞到 Delimiter 屬性中的分隔符字符
Public Function ReplaceAll() As String
mstrOriginal = MyBaseLine
Return MyBaseLineReplace( mstrDelimToChar())
End Function
ReplaceAll 方法通過基類的 Line 方法檢索原始文本行而以前從基類中檢索屬性時使用的是 MyBaseLine 語法ReplaceAll 函數將 MyBaseLine 屬性的值放入您剛剛為該類創建的 Private 變量 mstrOriginal 中String 數據類型的 Replace 方法將字符串字符的所有實例替換為在 Delimiter 屬性中設置的新分隔符字符 mstrDelim
MyBase 關鍵字
可以從任一子類使用 MyBase 關鍵字以調用基類中的任何屬性或方法即使基類的方法在子類中已被覆蓋您也可以使用該關鍵字對其進行調用例如如果在基類中存在 ReplaceAll 方法但在子類中該方法已被覆蓋您可以從子類的 ReplaceAll 方法中調用基類的 ReplaceAll 方法
試一試
打開 frmLineTestVB 窗體
雙擊 Replace(替換)以調出單擊事件過程
在 btnReplace 按鈕的單擊事件中編寫以下代碼
Protected Sub btnReplace_Click( _
ByVal sender As Object _
ByVal e As SystemEventArgs) Handles btnReplaceClick
Dim oLine As LineDelim = New LineDelim()
oLineDelimiter = txtDelimText
oLineLine = txtLineText
txtReplaceText = oLineReplaceAll()
End Sub
此代碼將 Delimiter 屬性設置為在示例窗體的 txtDelimiter 文本框中輸入的值然後您可以調用 ReplaceAll 方法將文本行中的所有空格更改為新的分隔符字符
按 F 鍵運行該項目
單擊 Replace(替換)您將看到在此按鈕旁邊的文本框中句中的每個詞之間都有一個逗號
覆蓋方法
添加 Delimiter 屬性後您可能想更改 LineDelim 類中的 GetWord 方法以便使用相應的分隔符替代 Line 類使用的單個空格因為您不一定想更改基類所以需要覆蓋 LineDelim 類中 GetWord 方法的功能在 LineDelim 類中創建新的 GetWord 方法之前您需要在 Line 類的 GetWord 方法聲明中添加一個關鍵字
在 Solution Explorer(解決方案資源管理器)窗口中打開 Linevb 類的代碼窗口
找到 GetWord 方法的聲明(聲明不包含參數)如下所示
Public Overloads Function GetWord() As String
在函數聲明中添加關鍵字 Overridable如下所示(沒有此關鍵字就無法覆蓋此方法)
Public Overridable Overloads Function GetWord() As String
打開 LineDelimvb 類並使用如下代碼添加新的 GetWord 方法
Public Overloads Overrides Function GetWord() As String
Dim astrWords() As String
astrWords = MyBaseLineSplit(mstrDelimToCharArray())
Return astrWords()
End Function
如果要更改基類中方法的功能則有必要在函數聲明中添加 Overrides 關鍵字現在LineDelim 類中的 GetWord 方法就可以使用 Delimiter 屬性的值來分隔句中的詞
如果只覆蓋其中一個 GetWord 方法則代碼只能查看這一個版本的方法而無法調用其他版本的 GetWord 方法要顯示所有方法您必須覆蓋每一個方法就象您在 LineDelim 類中所執行的操作一樣
試一試
按 F 鍵運行該項目
在句中的每個詞之間都輸入一個逗號並在 Delimiter(分隔符)文本框中輸入一個逗號
單擊 Get Word(取詞)
句中的第一個詞將出現在該按鈕旁邊的文本框中
抽象類
在本文上一部分的示例中我們學習了如何創建 Person 對象這是因為我們想處理普通的人但是您可能會發現如果不先添加一些特定的行為和/或數據就無法使用 Person 類執行任何操作因此您可以將 Person 類變為抽象類抽象類僅定義將由子類創建的一般屬性和方法
將 Person 類定義為只能被繼承的抽象類而不是在運行時實際創建的對象從該類繼承的每個類(如 Employee 類)都將使用特定的功能來創建所有相應的屬性和方法例如Employee 類將創建實際的 Print 方法而 Person 類僅定義必須存在 Print 方法Person 類中沒有與 Print 方法相關聯的代碼 使用抽象類的原因有多種對於強制子類設計人員實現應用程序通常所需的所有接口抽象類非常有用您可以在不破壞客戶端應用程序的情況下向子類添加新方法這是使用接口所無法實現的可以在基類中提供許多默認實現方法從而減少子類需要完成的工作量
接口繼承
創建抽象類時請使用關鍵字 Interface 而不是 Class為接口命名然後定義需要子類實現的所有屬性和方法這是因為基類中沒有可以實現的屬性和方法它只包含一般數據而不包含方法您所創建的只是一個合約它規定所有使用此接口的子類都必須遵循一定的規則
現在請在已創建的項目中添加一個新類
從 Visual Studio 菜單中單擊 Project(項目)然後單擊 Add Class(添加類)
在類中添加以下代碼
Interface Person
Property FirstName() As String
Property LastName() As String
Sub Print()
Sub Talk()
End Interface
您會發現您定義屬性和子過程的方法與您通常定義這些屬性和過程的方法一樣唯一的差別在於您沒有為它們編寫任何代碼現在來看看如何在類定義中使用此接口
在上一步驟創建的類文件中添加以下代碼
Public Class Employee
Implements Person
Private mstrFirstName As String
Private mstrLastName As String
Property FirstName() As String _
Implements PersonFirstName
Get
Return mstrFirstName
End Get
Set
mstrFirstName = Value
End Set
End Property
Property LastName() As String _
Implements PersonLastName
Get
Return mstrLastName
End Get
Set
mstrLastName = Value
End Set
End Property
Sub Print() Implements PersonPrint
在此處添加一些代碼
End Sub
Sub Talk() Implements PersonTalk
在此處添加一些代碼
End Sub
End Class
在 Employee 類定義之後的第一行是 Implements Person此關鍵字表示您要遵守 Person 接口中定義的合約現在您可以定義該合約中的所有屬性和方法在每一個 Property 語句後面都必須包含 Implements 關鍵字並且必須指定接口的名稱和您正在使用的方法/屬性的名稱(兩個名稱之間有一個點 [])Visual 將跟蹤每一個接口在所有接口創建完畢之前您不能編譯應用程序 如果要運行代碼則需要創建相應的子過程因為在上面的示例中這些子過程被保留為空創建所有子過程後您就可以與您通常創建並使用任何其他對象一樣聲明並使用新的 Employee 對象了
選擇要使用的繼承類型
有時候很難決定到底是使用實現繼承還是使用接口繼承很多情況下可能兩種繼承都會用到但都只涉及一小部分例如您可能需要在 Line 類中添加必須被子類覆蓋的方法定義在過程定義中使用 MustOverride 關鍵字即可實現此操作
Public MustOverride Sub Init()
將此定義添加到類中以後其作用類似於一個接口在子類中必須定義 Init 方法並且該方法必須使用 Overrides 關鍵字以下是如何定義 Init 方法的示例
Public Overrides Sub Init()
mstrDelim =
mstrLine = 測試行
End Sub
同樣請記住使用 Overrides 關鍵字該關鍵字用於通知編譯器此方法將覆蓋父類中的 Init 方法
注意 Microsoft NET 框架的聯機幫助中提供了設計指南可以幫助您決定要使用的繼承類型
阻止繼承在某些情況下您可能不希望其他類繼承您的類如果是這樣您可以使用關鍵字 NotInheritable 來阻止類的繼承
Public Class NotInheritable Employee
類定義
End Class
Visual Basic 以來的新增功能
使用 Visual Basic NET您可以繼承 NET 框架包含的所有類您可以創建自己的類使這些類繼承現有的類並通過對代碼進行簡單更改來添加或刪除功能
總結
本文介紹了如何繼承基類如何向基類添加其他屬性以及如何使用 Overrides 關鍵字來替換基類中定義的功能還介紹了使用 MyBase 關鍵字調用基類中的方法從而擴展基類的功能雖然繼承並不是對所有的應用程序都適用但如果使用正確繼承將成為一種非常強大的工具
From:http://tw.wingwit.com/Article/program/net/201311/11397.html