iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 12
0
自我挑戰組

.net 後端起手式 30天認識 C# 系列 第 12

DAY 12 繼承

繼承

繼承是物件導向程式設計的三個主要特性之一,另外兩個是封裝和多型。
繼承可讓您建立新類別以重複使用、擴充和修改其他類別中定義的行為。
成員被繼承的類別稱為「基底類別」,而繼承這種成員的類別即稱為「衍生類別」。
衍生類別只能有一個基底類別。 不過,繼承是可轉移的。如果 ClassC 衍生自 ClassB,而 ClassB 衍生自 ClassA,則 ClassC 會繼承在 ClassB 和 ClassA 中宣告的所有成員。

封裝(Encapsulation):簡單說就是我們前幾天提到的類別,透過存取層級關鍵字來決定哪些屬性與方法是公開或私有的。

多型(Polymorphism):個人認為多載的差異為,多載為單一類別存在同名稱但不同參數的方法,而多型則是不同類別共同存在的同名方法。

衍生類別可以重複使用基底類別中的程式碼,而不需要重新實作。
您可以在衍生類別中新增更多成員。透過這種方式,衍生類別等於是擴充了基底類別的功能。

也就是說當今天使用了繼承,ClassB 繼承了 ClassA 時不需要針對 ClassA 原有的方法重新撰寫內容。在這邊示範一下

class Program {
  static void Main (string[] args) {
    ClassB classB = new ClassB ();
    classB.SetA (6);
    classB.PrintA ();
    Console.ReadKey ();
  }
}
class ClassA {
  protected int a = 0;
  public void PrintA () {
    Console.WriteLine (a);
  }
}
class ClassB : ClassA {
  public void SetA (int number) {
    a = number;
  }
}

可以的話還是請讀者親自改改看,為什麼 ClassB 在 new 生成物件時,要由 SetA 來更改 a 值,繼承時什麼可以使用什麼不能使用,以及生成物件後哪些東西可以被存取,這都在第十天的存取層級關鍵字有說明了。

所以透過上述範例可以了解繼承的用法,再舉一個示範用途的常見例子,比如說動物,每種動物都有屬於自己的一些特性,如鳥會飛、魚會游泳等等,但他們都有共同生為動物的吃與睡覺。

所以基底類別為動物,衍生類別就是鳥與魚。

class Program {
  static void Main (string[] args) {
    Bird bird = new Bird ();
    bird.Eat ();
    bird.Sleep ();
    bird.Fly ();
    Fish fish = new Fish ();
    fish.Eat ();
    fish.Sleep ();
    fish.Swim ();
    Console.ReadKey ();
  }
}
class Animal {
  public void Eat () {
    Console.WriteLine ("進食");
  }
  public void Sleep () {
    Console.WriteLine ("閉眼睡覺");
  }
}
class Bird : Animal {
  public void Fly () {
    Console.WriteLine ("飛行");
  }
}
class Fish : Animal {
  public void Swim () {
    Console.WriteLine ("游泳");
  }
}

當然每種動物的吃與睡覺的方法不一樣,所以需要去重寫內容,例如睡覺方法,魚不會閉眼啊,所以我們需要透過 overridenew 關鍵字重新定義方法。

override:需要配合 virtualabstract 使用,基底內別需要將欲 override 的方法加上這兩個關鍵字,才可以進行衍生類別的方法覆寫。

virtual(虛擬方法) 與 abstract(抽象方法) 簡單來說就是 virtual 能實作方法,而 abstract 不能實作方法的差別。

new:將衍生類別重新定義一個同名稱的方法,但已存在的基底類別方法依然存在,所以在操作基底類別時,若使用基底類別的方法去呼叫這個同名稱的方法,則會出現基底類別的方法。

overridenew 簡單來說就是 override 是覆寫基底類別的方法,而 new 是衍生類別重新撰寫一個方法。

這邊示範 override 來改寫睡覺方法

class Program {
  static void Main (string[] args) {
    Bird bird = new Bird ();
    bird.Eat ();
    bird.Sleep ();
    bird.Fly ();
    Fish fish = new Fish ();
    fish.Eat ();
    fish.Sleep ();
    fish.Swim ();
    Console.ReadKey ();
  }
}
class Animal {
  public void Eat () {
    Console.WriteLine ("進食");
  }
  public virtual void Sleep () {
    Console.WriteLine ("閉眼睡覺");
  }
}
class Bird : Animal {
  public void Fly () {
    Console.WriteLine ("飛行");
  }
}
class Fish : Animal {
  public void Swim () {
    Console.WriteLine ("游泳");
  }
  public override void Sleep () {
    Console.WriteLine ("開眼睡覺");
  }
}

若衍生類別與基底類別擁有相同名稱的成員,但想要存取基底類別的成員時,則可以使用 base 關鍵字來表示基底類別。

若你想要避免被衍生,可以將類別本身或其成員宣告為密封 sealed,即可防止其他類別繼承該類別,或繼承其任何成員。

一些小結論

了解類別的這三個特性,就能撰寫一個好的物件導向程式,由基底類別為物件的共有成員,在為不同處生成其衍生類別,好處當然就是共有程式碼時,易讀易改。壞處則是新手不懂時,會不知道怎麼去拆物件,讀 code 時若不清楚,則好像要東看一塊西看一塊,所以物件導向該有什麼規範也要去了解,幫助每一個工程師去讀 code 寫 code。

題外話:個人比較少用繼承,而是會比較常用明天所介紹的「介面」,概念與繼承有極高相似。然後在引用官方說明時,有提到衍生類別只能有一個基底類別,在之前看的文章裡,可能以後 C# 會新增一個特性來支援多重繼承,但我忘記關鍵字了,所以可以期待一下。

參考連結
繼承 (C# 程式設計手冊) | Microsoft Docs
sealed (C# 參考) | Microsoft Docs


上一篇
DAY 11 類別(二)
下一篇
DAY 13 介面
系列文
.net 後端起手式 30天認識 C# 30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言