抽象類
何時必須聲明一個類為抽象類?(面試題)
當這個類中包含抽象方法時,或是該類並沒有完全實現父類的抽象方法時。
abstract 修飾符可用於類、方法、屬性、索引和事件。 在類聲明中使用 abstract
修飾符以指示某個類僅旨在作為其他類的基類。 標記為 abstract 的成員,或包含在抽象類中的成員,都必須由派生自抽象類的類來實現。
抽象類的特征:
- 抽象類由abstract關鍵字修飾,只能用作基類
- 抽象類可能包含抽象方法和訪問器,同時也可以包含非抽象方法和非抽象訪問器(只要有一個抽象方法,該類就必須定義為抽象類)
1 abstract class AbstractClass 2 { 3 public abstract int Age { get; }//抽象訪問器 4 public string Name { get { return "張三"; } }//非抽象訪問器 5 6 public abstract void AbstractMethod();//抽象方法 7 8 public void Method()//非抽象方法 9 { 10 Console.WriteLine("抽象類中的非抽象方法"); 11 } 12 }
- 派生自抽象類的非抽象類,必須實現抽象類的所有抽象方法和訪問器,否則該子類也必須聲明為抽象類
1 class MyClass : AbstractClass 2 { 3 //實現抽象類中的抽象訪問器 4 public override int Age 5 { 6 get 7 { 8 return 30; 9 } 10 } 11 //實現抽象類中的抽象方法 12 public override void AbstractMethod() 13 { 14 Console.WriteLine("在派生類中實現的抽象方法"); 15 } 16 }
- 抽象類不能被實例化(但是抽象類中可以有構造函數),只能通過派生類進行實例化
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 //AbstractClass abstractClass = new AbstractClass();//抽象類不能實例化,這種寫法會報錯 6 MyClass myclass = new MyClass(); 7 Console.WriteLine(myclass.Age);//30 8 Console.WriteLine(myclass.Name);//張三 9 myclass.Method();//抽象類中的非抽象方法 10 myclass.AbstractMethod();//在派生類中實現的抽象方法 11 12 Console.ReadKey(); 13 } 14 }
- 抽象類不能使用sealed修飾符來修飾,因為abstract和sealed兩個修飾符有相反的含義(sealed表示該類不能被繼承,abstract表示該類可以被繼承)
- 抽象類可以被抽象類繼承,此時抽象的派僧類可以對抽象基類中的抽象方法進行重寫,也可以不進行重寫,但是必須在該抽象派生類的子類中對其進行重寫
抽象方法和抽象訪問器
- 抽象方法使用abstract修飾,使用static和virtual修飾是錯誤的
- 抽象方法是隱式的虛方法
- 只有抽象類才允許聲明抽象方法
- 抽象方法只有方法簽名,沒有方法具體實現的方法體
- 在靜態屬性上是用abstract修飾符是錯誤的
- 通過override修飾符,可以在派生類中重寫抽象類中的抽象方法和抽象訪問器
- 抽象成員不能是私有的
虛方法
- 虛方法使用virtual關鍵字修飾
- 虛方法不能是私有的
- virtual修飾符不能與static、abstract、private、override修飾符一起使用
- 通過override關鍵字對虛方法進行重寫
1 class Class1 2 { 3 public virtual void ShowInfo() 4 { 5 Console.WriteLine("虛方法在父類中的實現"); 6 } 7 } 8 9 class Class2 : Class1 10 { 11 public override void ShowInfo() 12 { 13 Console.WriteLine("虛方法在子類中的實現"); 14 } 15 } 16 17 class Program 18 { 19 static void Main(string[] args) 20 { 21 Class2 c = new Class2(); 22 c.ShowInfo();//虛方法在子類中的實現 23 24 Console.ReadKey(); 25 } 26 }
1、當調用一個對象的函數時,系統會先去檢查這個對象所屬的類,看所調用的函數是否為虛函數;
2、如果不是虛函數,那么它就直接執行該函數。而如果有virtual關鍵字,也就是一個虛函數,那么這個時候它就不會立刻執行該函數了,而是轉去檢查對象的實例類。
3、在這個實例類里,他會檢查這個實例類的中是否重寫該虛函數(通過override關鍵字),如果是有,那么就馬上執行該實例類中的這個重新實現的函數;如果沒有的話,系統就會不停地往上找實例類的基類,直到找到第一個重寫了該虛函數的基類為止,然后執行該基類中的函數。
抽象方法與虛方法的區別:
- 抽象方法必須定義在一個抽象類中,虛方法沒有特殊要求
- 抽象方法在基類中不可以有具體的實現,而虛方法在基類中必須有具體的實現
- 抽象方法要求必須在派生類中對其進行重寫;而虛方法可以在派生類中對其進行重寫,也可以不對其進行重寫
抽象類與接口的相同點:
- 都可以被繼承
- 都不可以實例化
- 都可以包含方法聲明
- 派生類都必須實現其未實現的方法
抽象類與接口的區別:
- 抽象類可以定義字段、屬性,可以包含方法的實現,可定義的內容與非抽象類基本一致;而接口只能定義屬性、索引器、事件和方法聲明,不能包含字段和方法實現
- 抽象類是一個不完整的類,需要進一步細化擴展;而接口是一個行為規范
- 抽象類更多的是定義在一系列緊密相關的類之間;而接口大多數是關系疏松但都實現某一功能的類中
- 抽象類是從一系列相關對象中抽象出來的概念, 因此反映的是事物的內部共性;接口是為了滿足外部調用而定義的一個功能約定, 因此反映的是事物的外部特性
- 接口基本上不具備繼承的任何具體特點,它僅僅承諾了能夠調用的方法
- 可以用於支持回調,而繼承並不具備這個特征
- 抽象類實現的具體方法默認為虛的,但實現接口的類中的接口方法卻默認為非虛的,當然您也可以聲明為虛的
- 如果抽象類實現接口,則可以把接口中方法映射到抽象類中作為抽象方法而不必實現,而在抽象類的子類中實現接口中方法