C# 入門指南
單元 12 - 物件導向程式設計
繼承 (inheritance) 是讓類別 (class) 能從已經定義好的類別擴充功能,多型 (polymorphism) 則是讓物件在繼承關係之下,讓物件的型態可以有通用性
「繼承」的英文動詞原文為 inherit ,程式設計社群長久以來都翻譯成「繼承」,這裡沿用社群的習慣。然而「繼承」的中文隱含上一代死去,下一代得到上一代的東西、權利的意思,英文 inherit 卻是泛指什麼得到什麼,因此遺傳也可以用 inherit ,物件導向中的「繼承」比較接近遺傳的意思,因為程式執行的當下,父、子物件都是並存的。
繼承的寫法是在類別名稱用冒號,冒號後接所繼承的類別名稱,例如
class Elephant: Animal
這樣 Elephant 類別就繼承了 Animal 類別。
在繼承關係中,繼承自其他類別的類別稱之為子類別 (subclass) ,像是 Elephant 就是 Animal 的子類別,而被繼承的類別稱之為父類別 (superclass) ,像是 Animal 就是 Elephant 的父類別。
C# 的官方文件把父類別稱之為基底類別 (base class) ,子類別稱之為衍生類別 (derived class) ,基底類別與衍生類別偏向是 C++ 書籍的用詞,這裡按照程式設計社群裡,繼承、父類別、子類別的脈絡,所採取的翻譯詞來敘述。
以下寫成完整範例,同時示範多型的概念
using System;
using System.Collections.Generic;
namespace ClassDemo03
{
class Animal
{
protected string name;
public Animal()
{
name = "動物";
}
public Animal(string s)
{
name = s;
}
public void speak()
{
Console.WriteLine("哈囉,我是{0}....", name);
}
}
class Elephant: Animal
{
public Elephant()
{
name = "大象";
}
}
class Mouse: Animal
{
public Mouse()
{
name = "老鼠";
}
}
class Program
{
static void Main(string[] args)
{
var animals = new List<Animal>
{
new Animal(),
new Elephant(),
new Mouse()
};
foreach (var animal in animals)
{
animal.speak();
}
}
}
}
//《程式語言教學誌》的範例程式
// http://kaiching.org/
// 專案:ClassDemo03
// 檔名:Program.cs
// 功能:示範 C# 的類別
// 作者:張凱慶
Animal 為父類別,如下
class Animal
{
protected string name;
public Animal()
{
name = "動物";
}
public Animal(string s)
{
name = s;
}
public void speak()
{
Console.WriteLine("哈囉,我是{0}....", name);
}
}
裡頭定義一個 protected 欄位 (field) ,字串 (string) name
protected string name;
這裡 protected 的欄位可以被子類別繼承, private 則不行。
下面定義兩個 public 的建構子 (constructor)
public Animal()
{
name = "動物";
}
public Animal(string s)
{
name = s;
}
這叫做多載 (overloading) ,建構子可以多載,方法 (method) 也可以多載,多載是指可以提供不同參數列給相同名稱的建構子或方法,使得呼叫的時候可以用不同的參數 (parameter) 進行設定。
然後最後是 public 的 speak() 方法
public void speak()
{
Console.WriteLine("哈囉,我是{0}....", name);
}
speak() 方法印出欄位 name , public 的成員在存取上完全沒有限制,因此 public 都會被子類別繼承。
繼續下面是兩個子類別
class Elephant: Animal
{
public Elephant()
{
name = "大象";
}
}
class Mouse: Animal
{
public Mouse()
{
name = "老鼠";
}
}
Elephant 及 Mouse 都繼承自 Animal ,這裡只有定義兩者各自的建構子, Elephant() 將 name 設定為 "大象" , Mouse() 則是設定為 "老鼠" 。
底下 Program 類別中的 Main() 示範使用這三個類別,首先用關鍵字 var 宣告 animals 變數
var animals = new List<Animal>
{
new Animal(),
new Elephant(),
new Mouse()
};
關鍵字 var 宣告的變數可以不直接指定型態,由指派運算子設定的值來決定型態,例如上面 animals 是 List , List 之後用角括弧圍住 Animal 型態名稱,這是設定 List 裡頭的元素必須是 Animal 或 Animal 的子類別。
角括弧的寫法是泛型 (generics) 程式設計的概念,也就是在定義時先不明確設定型態,由建立實體物件時再實際設定。
List 是類似陣列 (array) 的資料型態,相較陣列有更多好用的方法。
底下用 foreach 迴圈裡的變數 animal 依序取得 animals 中的每個元素
foreach (var animal in animals)
{
animal.speak();
}
注意 animal 也是用 var 宣告的,這裡就用到了多型的概念,每一個 animal 都有 speak() 方法,而這個 speak() 方法是繼承自 Animal 類別。
執行結果如下
C:\ClassDemo03> dotnet run |
哈囉,我是動物.... |
哈囉,我是大象.... |
哈囉,我是老鼠.... |
C:\ClassDemo03> |
其實繼承、多型、泛型等等的程式設計概念,真的要講清楚都是大部頭的書,這裡先了解程式碼中出現什麼是什麼概念就好了,下一個單元繼續介紹介面 (interface) 、命名空間 (namespace) 與 using 。
相關教學影片
中英文術語對照 | |
---|---|
陣列 | array |
基底類別 | base class |
類別 | class |
建構子 | constructor |
衍生類別 | derived class |
欄位 | field |
泛型 | generics |
介面 | interface |
繼承 | inheritance |
方法 | method |
命名空間 | namespace |
多載 | overloading |
參數 | parameter |
多型 | polymorphism |
字串 | string |
子類別 | subclass |
父類別 | superclass |
參考資料 | |
---|---|
1. C# 程式設計手冊 | Microsoft Docs - 繼承 | |
2. C# 程式設計手冊 | Microsoft Docs - 多型 | |
3. C# 程式設計手冊 | Microsoft Docs - 泛型 |
重點整理 |
---|
1. 繼承是讓新定義的類別直接從已經存在的類別擴充功能,寫法是在子類別的後面加上冒號,冒號後接上父類別的名稱。 |
2. C# 的官方文件把父類別稱之為基底類別,子類別稱之為衍生類別。 |
3. 多載是提供不同參數列給相同名稱的建構子或方法,使得呼叫的時候可以用不同的參數進行設定。 |
4. 多型是不同子類別繼承自相同的父類別,這些子類別具有相同的方法,在使用上可以用父類別的型態名稱替代。 |
問題與討論 |
---|
1. 物件導向程式設計有哪三大基本特性? |
2. 什麼是繼承?繼承機制有什麼優點? |
3. 什麼是多型?可以用什麼方式比擬嗎? |