程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> 5、繼承和多態,5,繼承多態

5、繼承和多態,5,繼承多態

編輯:C#入門知識

5、繼承和多態,5,繼承多態


本學習主要參考Andrew Troelsen的C#與.NET4高級程序設計,這小節主要述說以下幾個東西: 1、如何使用繼承來構建一組相關類。 2、如何使用虛成員和抽象成員在類層次結構中創建多態接口。 3、.net基礎類庫中的超級父類System.Object。  

繼承的基本機制

繼承是OOP的一個方面,可以促進代碼重用,更具體地說,代碼重用歸為兩類,經典繼承(‘is-a’關系)和包含/委托模型(‘has-a’關系)。 is-a關系:類之間的is-a關系也就是在兩個或兩個以上類類型之間創建了依賴關系,經典繼承的基本思想是新類可以利用既有類的功能。 定義一個基類A如下: class A {     private int num;     public int Num     {         get{return num;}         set{num = value;}     }     public A()     {         Console.WriteLine(Num);     }     public A(int aaa)     {Console.WriteLine("this is A");} }

1、指定既有類的父類。

如果我們定義一個類B讓其繼承A則定義如下: class B:A {} 如此,我們B類便得到了A類裡面的公有類成員Num和公有方法構造函數A()。(繼承類不能訪問父類的私有成員,繼承保護了封裝)這樣就實現了代碼重用。

2、多個基類。

說道基類,要記住很重要的一點:C#要求一個類只能有一個直接基類。我們不能創建直接派生自兩個或兩個以上的基類的類類型(多重繼承)。不過,.net平台允許某一個類實現多個獨立的接口。這樣,C#類型可以實現很多行為,同時又避免了多重繼承引起的復雜性。還可以通過構建靈活的接口層次來建模復雜的行為。

3、sealed關鍵字。

C#提供了另外一個關鍵字sealed來防止發生繼承。如果我們將類標記為sealed,編譯器將不允許我們從這個類型派生。例如,我們將B改成下面形式: sealed class B:A {} 如果C類想要繼承B類的話,將會產生編譯錯誤。 class C:B//錯誤,不能擴展sealed標記的類。(string類是個密封的類,不能擴展。) {} 說明:C#結構總是隱式密封的,因此,我們永遠不可以從結構繼承結構,從類繼承結構或者從結構繼承類。結構只能用於建模獨立的、用戶自定義的數據類型。如果希望使用is-a關系,必須使用類。  

OOP的第二個支柱:繼承

1、使用base關鍵字來控制基類的創建。

C#下,一般基本的默認構造函數會在派生類構造函數執行之前被自動調用。為了幫助優化派生類的創建,最好實現子類構造函數,來顯示調用合適的自定義基類構造函數,而不是默認構造函數。 class B:A {public B(int a ):base(int aaa)} 說明一點,當我們為類定義增加了自定義的構造函數,默認構造函數就自動移除了。因此必要情況下,我們需要為子類重新定義默認構造函數。

2、家族的秘密:protected關鍵字。

我們已經知道,公共項可以在任何地方直接訪問,而私有項除了定義它的類之外,不能從其他對象進行訪問。C#提供了另外一個定義成員可訪問性的關鍵字:protected。 當基類定義了受保護數據或受保護成員時,它就創建了一組可以被任何後代訪問的項。 如A類增加如下定義,B類就可以訪問這些信息。 class A {protected int rC;} 這樣的好處,派生類不再需要使用公共方法或屬性來間接訪問數據了。 壞處,如果派生類有權直接訪問其父類內部數據,有可能會偶然繞過公共屬性內設置的既有業務規則。 最後要注意,對對象用戶來說,受保護數據可以認為是私有的。因此,如果B b = new B();b.rc=10;就會產生錯誤。

3、增加密封類。

密封類是不能被其他類擴展的,這項技術通常用於設計工具類。如果我們希望構建新類來使用密封類的功能,唯一的辦法就是使用包含/委托模型(也叫‘has-a’關系)。  

包含/委托編程

我們創建一個類C,和A類的邏輯表示為A類包含C類。如果我們更新A類則就如下: class A {     protected C c= new C(); } 然而,如果我們要公開被包含對象的功能給外部世界,就需要委托。簡單地說,委托就是增加公共成員到包含類,以便使用被包含對象的功能。 例如C類如下: class C { public void PrintC(){Console.WriteLine("this is C");}} A類如果想要使用C類的PrintC函數,需要增加如下定義 class A {     public void GetPrintC()     {return c.PrintC();} } 嵌套類型定義:這就是‘has-a’關系的另一種說法。在C#中我們可以直接在類或結構作用域定義類型(枚舉、類、接口、結構或委托),這樣做,被嵌套類型會被認為是嵌套類的成員,嵌套類型可以操作其他成員一樣來操作嵌套類型(可以訪問其中的私有成員): public Class D {     public class C{}//公共嵌套類型可以被任何人使用     private class C{}//私有嵌套類型只可以被包含類的成員使用。 }  

OOP的第三個支柱:C#的多態支持

1、virtual 和override關鍵字。

多態為子類提供了一種方式,使其可以定義由基類定義的方法,這種過程叫做方法重寫。如果基類希望定義可以由子類重寫的方法,就必須使用virtual關鍵字標志方法: partial class A {     public virtual void vA(int aaaaa){//操作邏輯} } 如果子類希望改變虛方法的實現細節,就必須使用override關鍵字。 class B:A {public override void vA(int aaaaa){//操作邏輯}} 注意,重寫方法完全可以通過base關鍵字來自由的使用默認行為,這樣我們就不需要完全重寫實現vA方法的邏輯。 public override void vA(int aaaa){base.vA(aaaaa);//其余的處理邏輯}

2、密封虛成員。

sealed關鍵字,它可以用於類類型來防止其他類型通過繼承擴展其行為。如果我們不希望密封整個類,而是只希望防止派生類來重寫某個虛方法,我們就可以在方法前添加sealed關鍵字: public override sealed void vA(int aaaaa){//處理邏輯}

3、抽象類。

由於許多基類都是比較模糊的實體,好的設計師會防止在代碼中直接創建基類的對象(實例)。在C#中我們可以使用abstract關鍵字來強制這種編程方式,因此創建一個抽象基類: abstract partial class A {...} 此時,A a= new A();就會產生錯誤。 盡管我們不能直接創建抽象類,但在創建其派生類時,仍然會在內存中對其進行組裝。因此對抽象類來說,定義若干在分配派生類時間接調用的構造函數是很正常的。

4、構建多態接口。

如果類被定義為抽象基類,它就可以定義許多抽象成員。當你希望定義沒有提供默認實現而必須在每個派生類中實現的成員時,可以使用抽象成員。這樣做就強制了每一個後代具有多態接口(不同於interface定義的接口)。 簡而言之,抽象基類的多態接口只是指一組虛的或者抽象的方法。 抽象方法和虛方法的區別:子類重寫虛方法不是必須的,但是每個子類強制被要求重寫基類的抽象方法。 說明:抽象方法只可以定義在抽象類中,如果不是這樣,會出現編譯錯誤。 標記abstract的方法是純粹的xieyi9。它之定義了名字、返回值和參數集合(沒有實現)。

5、成員投影。

C#提供了邏輯上和方法重寫相對的功能,奇偶做投影。正式的說,如果派生類定義的成員和定義在基類中的成員一致,派生類就投影了父類的版本。編譯會產生警告。解決問題的辦法如下: 1.我們可以只使用override關鍵字更新父類版本的成員。 2.我們可以為派生類型的相同成員添加new關鍵字。這樣就顯式聲明派生類型的實現故意設計為隱藏父類的版本。(相當於和父類沒有關系的成員) 我們還可以把new關鍵字應用到任何從基類繼承的成員類型中(字段、常量、靜態方法、屬性等)。相反,我們需要知道,我們也仍然可以使用顯式強制轉換來觸發陰影成員在基類中的實現。  

基類/派生類轉換規則

在.net平台下,系統中的最高基類是System.Object。因此,所有東西都是(‘is-a’)object,並且可以照此進行處理。 object obj=new A(); 類型之間強制轉換的第一條准則:如果兩個類通過is-a關系關聯,在基類引用中保存派生類型總是安全的。(隱式轉換) 類型之間強制轉換的第二條准則:使用C#強制轉換操作符進行顯式的向下轉換。(強制轉換)

1、C#的as關鍵字。

as關鍵字可以在運行時快速檢測某個類型是否和另外一個兼容。如果我們使用as關鍵字就可以通過檢查null返回值來檢測兼容性。

2、C#的is關鍵字。

C#語言提供了is關鍵字來檢測兩個項是否兼容。然而,和as關鍵字不同的是,如果類型不兼容,is關鍵字就返回false而不是null引用。 注意,我們不需要使用try/catch結構來包裝我們的強制轉換操作,因為我們知道有了這樣的條件檢測,代碼在if區域中的強制轉換一定是安全的。  

超級父類:System.Object

在.net世界中,每一個類型最終都會從一個叫做System.Object(可以用C#關鍵字object表示)的基類派生。Object類定義了一組框架中所有類型公共的成員。如果我們沒有顯式定義類的父類,編譯器會自動從Object派生我們的類型。盡管其內置的行為能滿足很多需要,但對於我們自定義類型來說,重寫一些繼承方法很常見: 重寫ToString()方法。 public override string ToString() {} 同重寫ToString方法類似,我們還可以重寫Equals方法、重寫GetHashCode方法等等。  

小結

本小節主要研究了繼承和多態的一些作用和細節。除此,我們還研究了如何在基類類型和派生類類型之間的顯示轉換。最後我們了解了一下超級父類System.Object的一些細節,結束了面向對象三大支柱繼承、封裝、多態的研究。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved