###### tags: `C#` # 抽象類別 (Abstract Class) ## 說明 抽象(abstract)通常表示一種想法、意念,而非真正的實體,當一個類別使用關鍵字 **abstract** 宣告,表示其為抽象類別,提供其他衍生類別共同的製作樣版。例如建築公司根據房屋樣版模型建造房屋,而各種房屋均擁有出入大門、各式起居房間、衛浴等共同的設施,但是門如何開、房間如何裝潢,則於建造完成進行裝潢時依據屋主需求而定。 抽象類別正是這樣的概念,就如同你無法住在只建好外觀的房屋裏是一樣的,**抽象類別本身無法產生實體物件,而且抽象類別包含了一個以上的抽象方法,這些方法只提供函式名稱與參數設定,並且由繼承的衍生類別實作,衍生類別同時必須實作所有抽象類別的方法,否則其本身將成為另一個抽象類別。** ![](https://i.imgur.com/r8nKsHK.png) 左邊的抽象類別 A 以虛線作表示,由於抽象類別並沒有完整的實作內容,因此無法建立成為物件實體,右邊則是繼承抽象類別的實體類別 B ,其中實作了抽象類別所定義的抽象成員`aMethod` 。 類別 B 由於完成了抽象成員`aMethod`的實作,因此本身是一個完整的類別,除了可以建立物件,同時可根據需求,進一步擴充其內容,就如同一般的類別。 ## 定義抽象類別 抽象類別由 **abstract** 關鍵字定義,底下為定義抽象類別的語法: ```csharp= abstract class TemplateClass ``` ## 定義抽象方法 抽象方法同樣必須以 **abstract** 關鍵字作宣告: ```csharp= abstract type method(parameter) ``` ## 實作抽象方法 **抽象方法本身只有定義,並且由繼承抽象類別的衍生類別進行實作,也就是在衍生類別當中覆寫這些抽象方法成員,就如同覆寫一般類別的虛擬(virtual)成員。** 抽象成員由於必須被衍生類別所覆寫,因此它本身即是一個具有`virtual`性質的成員,在衍生類別當中,覆寫這些抽象成員的實作方式與覆寫一般類別的`virtual`成員相同,同樣必須使用以下的敘述: ```csharp= override type method(parameter) ``` ## 範例 ### 建立抽象類別 以下是一個實際的抽象類別,模擬各種幾何形狀的邊長、面積與體積的計算功能,提供作為其他類別所需的基礎架構。 ```csharp= abstract class TemplateClass { //變數 len 代表所要計算的各種形狀邊長 public double len = 0; //建構式接受兩個參數,第一個參數 shape 為形狀種類名稱,第二個參數 r 為邊長 //物件建立時,根據所接受的參數,輸出目前所要測量的形狀,並且將邊長的參數值指定給類別層級變數 len public TemplateClass(string shape, double r) { this.TheShape(shape); this.len = r; } private void TheShape(string shape) { Console.WriteLine("目前測量的形狀為{0} ", shape); } //實體方法 GetResult 執行類別中三個周長、面積與體積計算功能的相關方法 public void GetResult() { Length(len); Area(len); Volume(len); } //Length、Area 與 Volume,這三個抽象方法,由衍生類別進行實作 public abstract void Length(double len); public abstract void Area(double len); public abstract void Volume(double len); } ``` ### 繼承抽象類別 接下來設計兩個繼承抽象類別的衍生類別,分別是`Square`與`Globe`,這兩個類別均引用`TemplateClass`類別的建構式,然後分別實作圓形與正方形的周長、面積以及體積的計算方法。 1. `Square`類別繼承`TemplateClass`,實作所有抽象方法成員,並且透過 **base** 關鍵字引用基礎類別的建構式。 > [base 教學](https://www.youtube.com/watch?v=1eAGN-NPBXE&list=WL&index=3) ```csharp= class Square : TemplateClass { //引用 TemplateClass 類別的建構式 public Square(string shape, double len) : base(shape, len) { } //利用 override 關鍵字,覆寫基礎類別的抽象方法 Length //實作正方形周長計算方法 protected override void Length(double len) { double squareLength = 4 * len; Console.WriteLine($"邊長為 {len} 的正方形周長 = {squareLength}"); } //利用 override 關鍵字,覆寫抽象方法 Area //實作正方形面積計算方法 protected override void Area(double l) { double area = Math.Pow(len, 2); Console.WriteLine($"邊長為 {len} 的正方形面積 = {area}"); } //利用 override 關鍵字,覆寫抽象方法 Volume //實作正方形體積計算方法 protected override void Volume(double l) { double volume = Math.Pow(len, 3); Console.WriteLine($"邊長為 {len} 的立方體體積 = {volume}"); } } ``` 2. `Globe`類別繼承`TemplateClass`,實作所有抽象方法成員,並且透過 **base** 關鍵字引用基礎類別的建構式。 ```csharp= class Globe : TemplateClass { public Globe(string shape, double r) : base(shape, r) { } protected override void Length(double r) { double globeLength = 4 * Math.PI * r; Console.WriteLine($"半徑為 {r} 的圓形周長 = {globeLength}"); } protected override void Area(double r) { double area = Math.PI * Math.Pow(r, 2); Console.WriteLine($"半徑為 {r} 的圓形面積 = {area}"); } protected override void Volume(double r) { double volume = (4/3) * Math.PI * Math.Pow(r, 3); Console.WriteLine($"半徑為 {r} 的球體體積 = {volume}"); } } ``` 3. 執行正方形和圓形周長、面積以及體積的計算方法 ```csharp= class Program { static void Main(string[] args) { const double len = 10; //建立 Square 的實體物件 Square mySquare = new Square("正方形", len); mySquare.GetResult(); Console.WriteLine(); //建立 Globe 的實體物件 Globe myGlobe = new Globe("圓形", len); myGlobe.GetResult(); Console.ReadLine(); } } ``` 4. 執行結果 ```htmlembedded= 目前測量的形狀為 正方形 邊長為 10 的正方形周長 = 40 邊長為 10 的正方形面積 = 100 邊長為 10 的立方體體積 = 1000 目前測量的形狀為 圓形 半徑為 10 的圓形周長 = 125.663706143592 半徑為 10 的圓形面積 = 314.159265358979 半徑為 10 的球體體積 = 3141.59265358979 ``` > 參考資料 * [抽象類別](http://www.kangting.tw/2018/11/blog-post.html) * [小山的 C# 教學-Abstract Class & Abstract Method](https://www.youtube.com/watch?v=i1Mnyu39ns4&list=WL&index=4)