您好,登錄后才能下訂單哦!
本文是深入淺出OOP第二篇,主要說說繼承的話題。
在OOP中,繼承有如下的定義:
繼承是一種OOP的機制,用于派生繼承預定義的類
在這個繼承關系中,預定義的類是基類,新類是子類
繼承常常用于實現代碼重用
繼承允許子類復用基類非private的的數據和方法
創建一個Console工程,命名為InheritanceAndPolymorphism。添加ClassA、ClassB類,并拷貝下面的代碼:
ClassA: class ClassA { } ClassB: class ClassB { public int x = 100; public void Display1() { Console.WriteLine("ClassB Display1"); } public void Display2() { Console.WriteLine("ClassB Display2"); } }
在Program.cs中,調用ClassA
class Program { static void Main(string[] args) { ClassA a = new ClassA(); a.Display1(); } }
如果運行,肯定會報錯的。
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 found
因為我們在ClassA中未定義Display1的方法。 下面我們重寫,使ClassA繼承自ClassB。
ClassA: class ClassA:ClassB { } ClassB:class ClassB { public int x = 100; public void Display1() { Console.WriteLine("ClassB Display1"); } public void Display2() { Console.WriteLine("ClassB Display2"); } }
再次運行,結果如下:
ClassB Display1
ClassA已經可以訪問其基類的Display1函數了,這個簡單的實例說明了繼承可復用基類的妙處,下面這張圖以父子財產繼承關系說明了繼承的意義
再來看另外一個場景,假設ClassA也有一個Display1函數,簽名和其基類一樣的:
class ClassA:ClassB { public void Display1() { System.Console.WriteLine("ClassA Display1"); } } ClassB:class ClassB { public int x = 100; public void Display1() { Console.WriteLine("ClassB Display1"); } public void Display2() { Console.WriteLine("ClassB Display2"); } }
執行后結果如下:
ClassA Display1
看起來結果是對的,ClassA默認調用了自己的Display1函數,但是Visual Studio有一個警告:
Warning: '
InheritanceAndPolymorphism.ClassA.Display1()
' hides inherited member 'InheritanceAndPolymorphism.ClassB.Display1()
'. Use thenew
keyword if hiding was intended.
C#中對方法的調用首先是查詢ClassA自己中有無Display1函數,再查詢其基類有無Display1函數。在基類和子類出現同樣函數的情況現實項目中是存在的,可能是基類代碼過于陳舊了,子類既想用同簽名的函數,又無法停止基類的同簽名函數,故會出現這樣的警告---盡管邏輯正確,但是這種設計還是有一些瑕疵的。
我們再試試在CalssA中通過base調用基類同名方法的情況:
ClassA: class ClassA:ClassB { public void Display1() { Console.WriteLine("ClassA Display1"); base.Display1(); } } ClassB:class ClassB { public int x = 100; public void Display1() { Console.WriteLine("ClassB Display1"); } public void Display2() { Console.WriteLine("ClassB Display2"); } }
執行結果如下:
ClassA Display1
ClassB Display1
這個實驗說明C#提供了base關鍵詞,用于在繼承中子類調用基類的函數或者變量(非private類型)。
同樣的,在ClassA.Display1中調用其基類的Display2也是可以的,代碼如下所示:
/// <summary> /// ClassB: acting as base class /// </summary> class ClassB { public int x = 100; public void Display1() { Console.WriteLine("ClassB Display1"); } public void Display2() { Console.WriteLine("ClassB Display2"); } } /// <summary> /// ClassA: acting as derived class /// </summary> class ClassA : ClassB { public void Display1() { Console.WriteLine("ClassA Display1"); base.Display2(); } } /// <summary> /// Program: used to execute the method. /// Contains Main method. /// </summary> class Program { static void Main(string[] args) { ClassA a = new ClassA(); a.Display1(); Console.ReadKey(); } }
執行結果如下:
ClassA Display1
ClassB Display2
那么可否通過基類調用其子類的函數呢?
/// <summary> /// ClassB: acting as base class /// </summary> class ClassB { public int x = 100; public void Display1() { Console.WriteLine("ClassB Display1"); } } /// <summary> /// ClassA: acting as derived class /// </summary> class ClassA : ClassB { public void Display2() { Console.WriteLine("ClassA Display2"); } } /// <summary> /// Program: used to execute the method. /// Contains Main method. /// </summary> class Program { static void Main(string[] args) { ClassB b = new ClassB(); b.Display2(); Console.ReadKey(); } }
運行報錯:
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'
運行的結果讓人抓狂
在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
'.
我們得出一個結論,C#中不許環形依賴繼承。
ClassB:public class ClassB { public int b = 100; } ClassA: public class ClassA { public int a = 100; }
Program.cs 代碼如下
/// <summary> /// Program: used to execute the method. /// Contains Main method. /// </summary> public class Program { private static void Main(string[] args) { ClassB classB = new ClassB(); ClassA classA = new ClassA(); classA = classB; classB = classA; } }
我們嘗試判斷ClassA、ClassB的對象是否可賦值。
編譯的結果是:報錯了
Cannot implicitly convert type 'InheritanceAndPolymorphism.ClassB' to 'InheritanceAndPolymorphism.ClassA' Cannot implicitly convert type 'InheritanceAndPolymorphism.ClassA' to 'InheritanceAndPolymorphism.ClassB'
盡管ClassA和ClassB里面的數據成員變量a數據一致,都為100,但是這里用等號比較的是類型--引用地址,故無法進行賦值。
我們再來試試繼承關系的:
public class ClassB { public int b = 100; } public class ClassA:ClassB { public int a = 100; } /// <summary> /// Program: used to execute the method. /// Contains Main method. /// </summary> public class Program { private static void Main(string[] args) { ClassB classB = new ClassB(); ClassA classA = new ClassA(); classA = classB; classB = classA; } }
ClassA繼承自ClassB,我們希望可以直接賦值其實例對象。
運行結果如下:
Error: Cannot implicitly convert type 'InheritanceAndPolymorphism.ClassB
' to 'InheritanceAndPolymorphism.ClassA
'.
運行結論:C#中子類對象可直接賦值給基類對象,基類對象需要往下強轉。代碼修改如下:
public class ClassB { public int b = 100; } public class ClassA:ClassB { public int a = 100; } /// <summary> /// Program: used to execute the method. /// Contains Main method. /// </summary> public class Program { private static void Main(string[] args) { ClassB classB = new ClassB(); ClassA classA = new ClassA(); classB=classA; classA = (ClassA)classB; } }
這樣編譯就通過了。
如果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)
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。