深刻淺出OOP(二): 多態和繼承(繼承)

本文是深刻淺出OOP第二篇,主要說說繼承的話題。ide

 

繼承的介紹

在OOP中,繼承有以下的定義:函數

  • 繼承是一種OOP的機制,用於派生繼承預約義的類spa

  • 在這個繼承關係中,預約義的類是基類,新類是子類設計

  • 繼承經常用於實現代碼重用code

  • 繼承容許子類複用基類非private的的數據和方法對象

繼承的實現

建立一個Console工程,命名爲InheritanceAndPolymorphism。添加ClassA、ClassB類,並拷貝下面的代碼:blog

  x =

 

Program.cs中,調用ClassA繼承

  Main(=

若是運行,確定會報錯的。接口

Error: 'InheritanceAndPolymorphism.ClassA' does not contain a definition for 'Display1' and no extension method 'Display1' accepting a first argument of type 'InheritanceAndPolymorphism.ClassA' could be foundip

由於咱們在ClassA中未定義Display1的方法。 下面咱們重寫,使ClassA繼承自ClassB。

  x =

 

再次運行,結果以下:

ClassB Display1

ClassA已經能夠訪問其基類的Display1函數了,這個簡單的實例說明了繼承可複用基類的妙處,下面這張圖以父子財產繼承關係說明了繼承的意義

image

 

再來看另一個場景,假設ClassA也有一個Display1函數,簽名和其基類同樣的:

   x =

執行後結果以下:

ClassA Display1

看起來結果是對的,ClassA默認調用了本身的Display1函數,可是Visual Studio有一個警告:

Warning: 'InheritanceAndPolymorphism.ClassA.Display1()' hides inherited member 'InheritanceAndPolymorphism.ClassB.Display1()'. Use the new keyword if hiding was intended.

C#中對方法的調用首先是查詢ClassA本身中有無Display1函數,再查詢其基類有無Display1函數。在基類和子類出現一樣函數的狀況現實項目中是存在的,多是基類代碼過於陳舊了,子類既想用同簽名的函數,又沒法中止基類的同簽名函數,故會出現這樣的警告---儘管邏輯正確,可是這種設計仍是有一些瑕疵的。

 

咱們再試試在CalssA中經過base調用基類同名方法的狀況:

   x =

 

執行結果以下:

ClassA Display1

ClassB Display1

這個實驗說明C#提供了base關鍵詞,用於在繼承中子類調用基類的函數或者變量(非private類型)。

 

image

 

一樣的,在ClassA.Display1中調用其基類的Display2也是能夠的,代碼以下所示:

 
    
     x =    
     
      
     
      Main(=

 

執行結果以下:

ClassA Display1

ClassB Display2

 

那麼能否經過基類調用其子類的函數呢?

 
    
     x =   
     
      
     
      Main(=

 

運行報錯:

Error: 'InheritanceAndPolymorphism.ClassB' does not contain a definition for 'Display2' and no extension method 'Display2' accepting a first argument of type 'InheritanceAndPolymorphism.ClassB' could be found

緣由是繼承沒法實現逆向調用,既基類沒法調用子類。

除了構造函數和析構函數,子類繼承了其基類的一些(包括private的成員變量和成員函數,只是沒法訪問)。

在C#中,一個類默認繼承的是object類型,object是C#全部引用類型的基類;同時,繼承具備傳遞性,如ClassC繼承自ClassB,ClassB繼承自ClassA,則ClassC可徹底複用ClassA的數據和函數---ClassC繼承了ClassA。

C#中全部的類型均可被繼承嗎?

public class ClassW : System.ValueType   {   }   public class ClassX : System.Enum   {   }   public class ClassY : System.Delegate   {   }   public class ClassZ : System.Array   {   }

執行結果:

'InheritanceAndPolymorphism.ClassW' cannot derive from special class 'System.ValueType'

'InheritanceAndPolymorphism.ClassX' cannot derive from special class 'System.Enum'

'InheritanceAndPolymorphism.ClassY' cannot derive from special class 'System.Delegate'

'InheritanceAndPolymorphism.ClassZ' cannot derive from special class 'System.Array'

 

運行的結果讓人抓狂

image

在C#中,自定義類沒法繼承自C#內置的一些類,如System.ValueType, System.Enum, System.Delegate, System.Array, etc。

 

下面這個例子咱們再看看C++中的多類繼承是否可在C#中實現:

    public class ClassW    {    }    public class ClassX    {    }    public class ClassY : ClassW, ClassX    {    }

執行結果:

Compile time Error: Class 'InheritanceAndPolymorphism.ClassY' cannot have multiple base classes: 'InheritanceAndPolymorphism.ClassW' and 'ClassX'.

 

執行結論是:C#僅支持單類繼承,不支持C++的這種星型繼承關係。 要使用星型繼承關係,請用接口實現。

 

那麼能否實現循環依賴繼承呢?

   public class ClassW: ClassY    {    }    public class ClassX: ClassW    {    }    public class ClassY :  ClassX    {    }

 

代碼邏輯很簡單,ClassW繼承自ClassY,ClassX繼承自ClassW, ClassY繼承自ClassX。

可是編譯後報錯了:

Error: Circular base class dependency involving 'InheritanceAndPolymorphism.ClassX' and 'InheritanceAndPolymorphism.ClassW'.

image

 

咱們得出一個結論,C#中不準環形依賴繼承。

 

實例對象的是否可賦值

   b =    a =

 

Program.cs 代碼以下

 
     
        Main(= = ==

 

咱們嘗試判斷ClassA、ClassB的對象是否可賦值。

編譯的結果是:報錯了

Cannot implicitly convert type 'InheritanceAndPolymorphism.ClassB' to 'InheritanceAndPolymorphism.ClassA' Cannot implicitly convert type 'InheritanceAndPolymorphism.ClassA' to 'InheritanceAndPolymorphism.ClassB'

image

儘管ClassA和ClassB裏面的數據成員變量a數據一致,都爲100,可是這裏用等號比較的是類型--引用地址,故沒法進行賦值。

 

咱們再來試試繼承關係的:

   b =    a =  
     
        Main(= = ==

 

ClassA繼承自ClassB,咱們但願能夠直接賦值其實例對象。

 

運行結果以下:

Error: Cannot implicitly convert type 'InheritanceAndPolymorphism.ClassB' to 'InheritanceAndPolymorphism.ClassA'.

運行結論:C#中子類對象可直接賦值給基類對象,基類對象須要往下強轉。代碼修改以下:

   b =    a =  
     
        Main(= = ==

 

這樣編譯就經過了。

若是ClassA不繼承自ClassB,則這種強轉在C#中是會報錯的:

Cannot convert type 'InheritanceAndPolymorphism.ClassA' to 'InheritanceAndPolymorphism.ClassB'

Cannot convert type 'InheritanceAndPolymorphism.ClassB' to 'InheritanceAndPolymorphism.ClassA'

 

 

本節結論

  • 沒法阻止子類覆蓋基類同簽名方法

  • 繼承關係是子類的同簽名方法先查找,再查找其基類的

  • base關鍵字被C#用於在子類中調用基類函數、變量

  • 繼承關係不可逆轉

  • 除了構造函數、析構函數,子類繼承了基類的一些

  • 自定義類默認繼承自Object類型,可是C#的這些類型不能被繼承:System.ValueType, System.Enum, System.Delegate, System.Array, etc.

  • C#不支持從多類繼承

  • C#不支持循環繼承

  • 子類對象可直接賦值給基類,反之須要強轉

 

原文地址:Diving in OOP (Day 2): Polymorphism and Inheritance (Inheritance)

相關文章
相關標籤/搜索