C# 入門指南

單元 12 - 物件導向程式設計

~~學習進度表~~

繼承 (inheritance) 是讓類別 (class) 能從已經定義好的類別擴充功能,多型 (polymorphism) 則是讓物件在繼承關係之下,讓物件的型態可以有通用性

Inheritance, 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) 進行設定。

然後最後是 publicspeak() 方法

public void speak()
{
    Console.WriteLine("哈囉,我是{0}....", name);
}

speak() 方法印出欄位 namepublic 的成員在存取上完全沒有限制,因此 public 都會被子類別繼承。

繼續下面是兩個子類別

class Elephant: Animal
{
    public Elephant()
    {
        name = "大象";
    }
}

class Mouse: Animal
{
    public Mouse()
    {
        name = "老鼠";
    }
}

ElephantMouse 都繼承自 Animal ,這裡只有定義兩者各自的建構子, Elephant()name 設定為 "大象"Mouse() 則是設定為 "老鼠"

底下 Program 類別中的 Main() 示範使用這三個類別,首先用關鍵字 var 宣告 animals 變數

var animals = new List<Animal>
{
    new Animal(),
    new Elephant(),
    new Mouse()
};

關鍵字 var 宣告的變數可以不直接指定型態,由指派運算子設定的值來決定型態,例如上面 animalsListList 之後用角括弧圍住 Animal 型態名稱,這是設定 List 裡頭的元素必須是 AnimalAnimal 的子類別。

角括弧的寫法是泛型 (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

相關教學影片

上一頁 單元 11 - 建構子與屬性
回 C# 入門指南首頁
下一頁 單元 13 - 介面、命名空間與 using
回 C# 教材首頁
回程式語言教材首頁
中英文術語對照
陣列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. 什麼是多型?可以用什麼方式比擬嗎?