Microsoft .NET 中的基類繼承 升級到 Microsoft .NET Paul D. Sheriff PDSA, Inc. 2001 年 12 月 摘要:本文介紹了繼承,說明了如何繼承基類,並且介紹了 Microsoft .NET 中的實現繼承和接口繼承。 目標
前提條件要徹底理解本文內容,需要滿足以下條件:
目錄繼承概述面向對象編程 (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 方法,以便使用此分隔符(而不是空格)分隔文本行並搜索第一個詞。 構建示例窗體圖 1 中顯示的示例窗體將用來測試要創建的繼承類。 圖 1:用於測試繼承的示例窗體
構建 Line 類 接下來將構建要繼承的 Line 類。
創建子類既然窗體和基類都已經創建完畢,現在便可以開始執行繼承了。
因爲添加了 Inherits Line 語句,所以您可以在這一新創建的類中使用 Line 類的所有屬性和方法。 試一試
Inherits 語句的功能非常強大,只需要使用這一個語句,就可以在 LineDelim 類中使用 Line 類的所有屬性和方法。儘管這個新類尚未執行任何新的操作,但它卻表明從 Line 類中繼承的所有代碼都可以正常工作。 添加其他功能現在,您可以使用其他屬性和方法對 LineDelim 類進行擴展。要向 LineDelim 類添加兩個新的屬性,請執行以下步驟。
現在您可以使用 Delimiter 屬性設置並獲取 Private 變量 mstrDelim 的值。 如果不希望其他人更改這些屬性,您可以將屬性設爲只讀。要執行此操作,請不再使用 Set 語句,並在 Property 語句中添加 ReadOnly 屬性。有關示例,請參見上面代碼中顯示的 OriginalLine 屬性聲明。 接下來,需要創建一個稱爲 ReplaceAll 的方法,此方法可以將文本行中的所有空格替換爲傳遞到 Delimiter 屬性中的分隔符字符。 Public Function ReplaceAll() As String mstrOriginal = MyBase.Line Return MyBase.Line.Replace(" ", mstrDelim.ToChar()) End Function ReplaceAll 方法通過基類的 Line 方法檢索原始文本行。而以前從基類中檢索屬性時使用的是 MyBase.Line 語法。ReplaceAll 函數將 MyBase.Line 屬性的值放入您剛剛爲該類創建的 Private 變量 mstrOriginal 中。String 數據類型的 Replace 方法將字符串字符的所有實例替換爲在 Delimiter 屬性中設置的新分隔符字符 mstrDelim。 MyBase 關鍵字可以從任一子類使用 MyBase 關鍵字,以調用基類中的任何屬性或方法。即使基類的方法在子類中已被覆蓋,您也可以使用該關鍵字對其進行調用。例如,如果在基類中存在 ReplaceAll 方法,但在子類中該方法已被覆蓋,您可以從子類的 ReplaceAll 方法中調用基類的 ReplaceAll 方法。 試一試
覆蓋方法添加 Delimiter 屬性後,您可能想更改 LineDelim 類中的 GetWord 方法,以便使用相應的分隔符替代 Line 類使用的單個空格。因爲您不一定想更改基類,所以需要覆蓋 LineDelim 類中 GetWord 方法的功能。在 LineDelim 類中創建新的 GetWord 方法之前,您需要在 Line 類的 GetWord 方法聲明中添加一個關鍵字。
如果要更改基類中方法的功能,則有必要在函數聲明中添加 Overrides 關鍵字。現在,LineDelim 類中的 GetWord 方法就可以使用 Delimiter 屬性的值來分隔句中的詞。 如果只覆蓋其中一個 GetWord 方法,則代碼只能查看這一個版本的方法,而無法調用其他版本的 GetWord 方法。要顯示所有方法,您必須覆蓋每一個方法,就象您在 LineDelim 類中所執行的操作一樣。 試一試
抽象類在本文上一部分的示例中,我們學習瞭如何創建 Person 對象,這是因爲我們想處理普通的人。但是您可能會發現,如果不先添加一些特定的行爲和/或數據,就無法使用 Person 類執行任何操作。因此您可以將 Person 類變爲抽象類,抽象類僅定義將由子類創建的一般屬性和方法。 將 Person 類定義爲只能被繼承的抽象類,而不是在運行時實際創建的對象。從該類繼承的每個類(如 Employee 類)都將使用特定的功能來創建所有相應的屬性和方法。例如,Employee 類將創建實際的 Print 方法,而 Person 類僅定義必須存在 Print 方法;Person 類中沒有與 Print 方法相關聯的代碼。 使用抽象類的原因有多種。對於強制子類設計人員實現應用程序通常所需的所有接口,抽象類非常有用。您可以在不破壞客戶端應用程序的情況下向子類添加新方法,這是使用接口所無法實現的;可以在基類中提供許多默認實現方法,從而減少子類需要完成的工作量。 接口繼承創建抽象類時,請使用關鍵字 Interface 而不是 Class。爲接口命名,然後定義需要子類實現的所有屬性和方法。這是因爲基類中沒有可以實現的屬性和方法,它只包含一般數據,而不包含方法。您所創建的只是一個合約,它規定所有使用此接口的子類都必須遵循一定的規則。
在 Employee 類定義之後的第一行是 Implements Person。此關鍵字表示您要遵守 Person 接口中定義的合約。現在您可以定義該合約中的所有屬性和方法。在每一個 Property 語句後面,都必須包含 Implements 關鍵字,並且必須指定接口的名稱和您正在使用的方法/屬性的名稱(兩個名稱之間有一個點 [.])。Visual Basic .NET 將跟蹤每一個接口,在所有接口創建完畢之前,您不能編譯應用程序。 如果要運行代碼,則需要創建相應的子過程,因爲在上面的示例中這些子過程被保留爲空。創建所有子過程後,您就可以與您通常創建並使用任何其他對象一樣,聲明並使用新的 Employee 對象了。 選擇要使用的繼承類型有時候很難決定到底是使用實現繼承還是使用接口繼承,很多情況下,可能兩種繼承都會用到,但都只涉及一小部分。例如,您可能需要在 Line 類中添加必須被子類覆蓋的方法定義,在過程定義中使用 MustOverride 關鍵字即可實現此操作。 Public MustOverride Sub Init() 將此定義添加到類中以後,其作用類似於一個接口。在子類中,必須定義 Init 方法,並且該方法必須使用 Overrides 關鍵字。以下是如何定義 Init 方法的示例: Public Overrides Sub Init() mstrDelim = " " mstrLine = "測試行" End Sub 同樣,請記住使用 Overrides 關鍵字。該關鍵字用於通知編譯器此方法將覆蓋父類中的 Init 方法。 注意:
阻止繼承在某些情況下,您可能不希望其他類繼承您的類。如果是這樣,您可以使用關鍵字 NotInheritable 來阻止類的繼承。 Public Class NotInheritable Employee ' 類定義 End Class Visual Basic 6.0 以來的新增功能使用 Visual Basic .NET,您可以繼承 .NET 框架包含的所有類。您可以創建自己的類,使這些類繼承現有的類;並通過對代碼進行簡單更改來添加或刪除功能。 總結本文介紹瞭如何繼承基類,如何向基類添加其他屬性,以及如何使用 Overrides 關鍵字來替換基類中定義的功能。還介紹了使用 MyBase 關鍵字調用基類中的方法,從而擴展基類的功能。雖然繼承並不是對所有的應用程序都適用,但如果使用正確,繼承將成爲一種非常強大的工具。 關於作者Paul D. Sheriff 是 PDSA, Inc. 的所有者。該公司位於南加利福尼亞州,是一家自定義軟件開發和諮詢公司。Paul 是南加利福尼亞的 MSDN 區域總監,著有《Paul Sheriff Teaches Visual Basic》一書,他爲 Keystone Learning Systems 製作了 70 多套關於 Visual Basic、SQL Server、.NET 和 Web 開發的視頻教材,最近還將與 Ken Getz 合作出版一本關於 SAMS 的書,書名是《ASP.NET Jumpstart》。有關詳細信息,請訪問 PDSA, Inc. 的 Web 站點 www.pdsa.com。 關於 Informant Communications GroupInformant Communications Group, Inc. 是一家專注於信息技術行業的多媒體公司。它成立於 1990 年,專門從事軟件開發出版物、會議、目錄發佈和 Web 站點等業務。ICG 在美國和英國均設有辦事處,目前已成爲享有盛譽的媒體和營銷內容集成商,並以高質量的技術信息滿足 IT 人員不斷增長的需求。 |
Microsoft .NET 中的基類繼承
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.