C#類的多態性:base、new、override、virtual

   本篇博客我們來學習面向對象的多態性,多態性主要的表現形式就是在繼承中當派生類從基類繼承時,它會獲得基類的所有方法、字段、屬性和事件。當父類和子類的成員簽名相同的時候,我們可以定義讓子類的這個同名成員以何種形式顯示出來,父類的這個的成員在子類中又用何種方式存在,這種多面的表現方法我們稱爲多態。如果我們要更改基類的數據和功能時,也就是說子類中可以以自己的方式去實現父類的功能,有兩種方式:1.我們還在子類中可以使用override關鍵字重寫基類中用virtual關鍵字修飾的虛擬的基成員;2.可以在子類中使用new關鍵字讓派生成員替換基成員,此時基類成員只是被有意的隱藏掉了。

舉一個現實生活的例子,我們來理解一下多態,爸爸如果有一套房子留給了兒子,並對兒子說:這個房子我裝修了一下,如果你不喜歡這個風格,可以自己再重新翻新一下,但是我就有一個要求,就是這個房子唯一不變就是我喜歡的掛在走廊牆上的一張油畫,你不許拆掉它。兒子欣然同意,拿到鑰匙去看了看房子,兒子有點對爸爸的審美產生了質疑,裝修的風格也太古樸了,於是兒子決定把客廳和臥室全部裝修了,改成了後現代主義的風格,這時發生了我們所說的多態的第一種方式,被稱爲重寫或覆寫,爸爸給房子時,把允許重新裝修的地方用virtual關鍵字修飾,兒子就可以用override關鍵字修飾那些允許重新裝修的房間,這時父親來到這個房子時會發現房子的客廳和臥室全部改變了。裝修完客廳和臥室後,兒子怎麼看都覺得走廊上的油畫太格格不入了,因爲油畫的內容是田園風情,這時兒子想起爸爸不讓動這幅畫,所以兒子想到了一個方法,就買了一副新的抽象派的油畫蓋在爸爸的畫上面,這樣爸爸如果來到家,想看自己的畫,也是存在的,這時發生的就是第二種方式,如果爸爸想在兒子的房子裏看自己的東西,就使用base關鍵字,兒子的新油畫用new關鍵字隱藏住爸爸的話。

  通過這個例子我們應該就能理解一點多態的含義了,我們先來學習第一種情況:重寫。在使用重寫的時候,一定要注意到一點,就是爲了讓子類可以完全的重寫父類中的成員,父類在定義這些成員的時候,一定要使用virtual關鍵字,讓可以重寫的方法成爲虛方法,讓可以重寫的屬性成爲虛屬性,子類在重寫這個方法或屬性的時候,將virtual替換成override關鍵字,代表已將父類的成員替換爲了它自己的成員並實現。我們來看一下具體的語法,爲了舉例方便,我採用的是方法重寫的實例,如:

 

 class FatherClass

{public virtual  void  Method(){}}

class SonClass:FatherClass

{public override  void  Method(){}}

  大家來看看父類中的方法,按照我們上節課所學的如果父類中的成員不是private修飾時,子類中是都可以訪問到一個成員,但是重寫是特殊的,根據我舉的例子大家回憶一下,這時如果父親來到兒子的房子,將會只存在被兒子重新裝修的客廳和臥室,這兩個屋原來的風格都不存在了。也就是說,在子類中,這兩個屋子只有一種形態,就是兒子重新裝修定義的。雖然其他的屋子父親也允許兒子裝修,使用了virtual關鍵字修飾了,但是因爲兒子沒有使用override關鍵字重新裝修,其他幾個屋的表現形態還是父親原先存在的。這就說明了一點,子類要想重寫父類的方法,必須是父類定義了virtual,子類使用override。當如果我想在子類的方法中再用父類的那個被覆蓋的方法時,只需要使用base關鍵字就可以代表繼承的父類了,base關鍵字我們在上節課的類七構造方法的繼承中也學到過。我們把上面的語法在子類的Method方法中,加base用法,基本語法如下:

public override  void  Method()

{

base.Method()

}

 這樣的話,在調用子類的Method方法時,雖然重寫了這個方法,但是使用base關鍵字又再次引用了父類的Method方法。

      當父類定義了virtual,而子類的同名方法沒有使用override重寫,這樣是可以的,這時子類中仍然包括父類的方法,也就是說子類中有兩個同名的方法,但是編譯器在我們創建子類對象的時候,會顯示子類的方法,而不會顯示繼承自父類那個同名的方法。如果你使用VS編譯這樣情況時,它會有一個警告:子類的方法將隱藏父類的方法。如果想重寫請在子類中加入override關鍵字,如果想隱藏請使用new關鍵字。使用override關鍵字剛纔我們已經講過了,如果用new就代表創建一個新的方法,這個子類中的新方法隱藏父類的方法,這就是我們說的第二種多態的形式隱藏父類的方法。

         隱藏父類方法,父類可以是virtual修飾的虛方法,也可以是普通方法應該在子類中顯式的使用new關鍵字,告知編譯器當調用子類的這個方法時,請顯示出子類自定義的功能,當然如果要顯示父類的方法也同樣可以使用base關鍵字,我們來看下面的語法:

    class FatherClass

{public   void  Method(){}}

    class SonClass:FatherClass

{public new  void  Method()

{

base.Method()

}

}

 我今天所舉出的實例比較簡單,就是定義了3個類一個包含入口函數的Program類、一個F類,一個S類繼承了F類,在FS中各定義了3個方法,對照結果我們來看一下:

重寫和隱藏父類方法實例

 1 //定義一個F類
  2    class F
  3    {
  4        //定義一個公有Method方法,子類中用new隱藏了本方法
  5        public void Method()
  6        {
  7            Console.WriteLine("我是父類中的Method方法");
  8            Console.WriteLine();
  9        }
 10        //定義了一個虛方法Method1,子類中重寫了Method1.
 11        public virtual void Method1()
 12        {
 13            Console.WriteLine("我是父類中的Method1方法");
 14            Console.WriteLine();
 15        }
 16        //定義了一個虛方法Method2,子類中重寫了Method2.子類中使用了base.method1,再次調用被重寫了的Method1
 17        public virtual void Method2()
 18        {
 19            Console.WriteLine("我是父類中的Method2方法");
 20            Console.WriteLine();
 21        }
 22    }
 23    //定義一個繼承F類的S類
 24    class S : F
 25    {
 26        //定義一個公有Method方法,隱藏了父類的方法
 27        public new void Method()
 28        {
 29            Console.WriteLine("我是子類中的Method方法,使用new關鍵字,顯式的隱藏父類中的同名方法");
 30            Console.WriteLine();
 31        }
 32        //定義一個重寫父類Method1的方法Method1。
 33        public override  void Method1()
 34        {
 35            Console.WriteLine("我是子類中的Method1方法,覆蓋父類中的同名方法,此時S中沒有了父類中Method1方法");
 36            Console.WriteLine();
 37        }
 38        //定義一個重寫父類Method1的方法Method1,同時使用base調用父類的Method1。
 39        public override  void Method2()
 40        {
 41          
 42            Console.WriteLine("我是子類中的Method2,覆蓋父類中的同名方法,調用base.method1");
 43            base.Method1();
 44            Console.WriteLine();
 45        }
 46    }
 47
 48
 49    class Program
 50    {
 51        static void Main(string[] args)
 52        {
 53            // 創建一個S類的s對象
 54            S s = new S();
 55            // 創建一個F類的f對象
 56            F f = new F();
 57
 58            //創建一個F類的fs對象,但是用S類來實現,這種方式是允許的。
 59            //意思就是父親到了兒子的房子去了,看到的油畫應該是父親的油畫,房子還是從父親那繼承下的房子。
 60            //對象fs所引用出的成員,實際是從父類中繼承來的成員,不是繼承來的成員(如兒子自己買的電器)fs是無權訪問的。
 61            //父類需要子類去實現的這種方式會在抽象類和接口中會用到。
 62            F fs = new S();
 63
 64            //先觀察一下子類使用new的Method方法中三對象的結果。
 65             //-------------------------------------------
 66            //子類的對象s引用的Method方法打印出的是子類的Method方法
 67            s.Method();
 68            //子類中的Method方法,因爲使用了new,只是覆蓋了父類的Method方法,
 69            //所以父類的對象fs引用的Method方法打印出的是還是從父類中繼承下來的Method方法
 70            fs.Method();
 71            //父類中的Method方法不變
 72            f.Method();
 73            Console.WriteLine("---------");
 74
 75
 76            //先觀察一下子類使用override的Method1方法中三對象的結果。
 77            //-------------------------------------------
 78            //子類的對象s引用的Method1方法打印出的是子類的Method1方法
 79            s.Method1();
 80            //子類中的Method1方法,因爲使用了override,重寫了父類的Method1方法,
 81            //所以父類的對象fs引用的Method1方法打印出的是還是從子類中繼承下來的Method1方法
 82            //子類中只存在子類的Method1方法,結果如上.
 83            fs.Method1();
 84            //父類中的Method方法不變
 85            f.Method1();
 86            Console.WriteLine("---------");
 87
 88
 89            //先觀察一下子類使用override和base.method1的Method2方法中三對象的結果。
 90            //-------------------------------------------
 91            //因爲使用了override,重寫了父類的Method2方法,
 92            //因爲使用了base.Method1,所以在子類中會調用父類的Method1方法
 93            //子類的對象s引用的Method1方法打印出的是子類的Method2方法和父類的Method1方法
 94            s.Method2();
 95            //子類中的Method2方法,因爲使用了override,重寫了父類的Method2方法,
 96            //所以父類的對象fs引用的Method2方法打印出的是還是從子類中繼承下來的Method2方法
 97            //子類中只存在子類的Method2方法,結果如上.
 98            fs.Method2();
 99            //父類中的Method方法不變
100            f.Method2();
101            Console.WriteLine("---------");
102        }
103    }
 
 
結果如下:
我是子類中的Method方法,使用new關鍵字,顯式的隱藏父類中的同名方法
我是父類中的Method方法
我是父類中的Method方法
---------
我是子類中的Method1方法,覆蓋父類中的同名方法,此時S中沒有了父類中Method1方法
我是子類中的Method1方法,覆蓋父類中的同名方法,此時S中沒有了父類中Method1方法
我是父類中的Method1方法
---------
我是子類中的Method2,覆蓋父類中的同名方法,調用base.method1
我是父類中的Method1方法

我是子類中的Method2,覆蓋父類中的同名方法,調用base.method1
我是父類中的Method1方法

我是父類中的Method2方法
---------
請按任意鍵繼續. . .
 
         在Method2方法中我寫base.Method1(),就想告訴大家,base關鍵字可以調用出父類所能繼承到子類的任何一個成員,同學們課下也可以試一試下面兩種情況:一,如果父類使用virtual,子類使用new,建立第4種Method4方法,也同樣執行這三種對象調用Method4,結果應該和Method方法一致的。還是印證了我說過的當子類中用new時,無論父類是虛方法還是普通方法,都會隱藏父類方法。二,如果同學在子類中只出現override關鍵字,而父類中沒有virtual相呼應,編譯器是會報錯的。
        相信通過這個實例大家應該會應用這四個關鍵字了,可以有的同學還是不明白父類用子類來實現的方式,沒關係!用我說的爸爸到兒子家的例子仔細想想就能明白了,這種用法最常見的形式就是當抽象類和接口要實例成對象的時候,都是採用子類來實現的,我們下節課會講到。



 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章