Download presentation
Presentation is loading. Please wait.
1
第7章 繼承/多型/介面 注意: 本投影片僅供本書上課教師使用,非經同意請勿上網轉載或供拷貝
2
第七章 繼承、多型、介面 7.1 繼承 (Inheritance) 7.2 靜態成員(Static Members)
7.3 多形(Polymorphism) 7.4 介面與實作 7.5 delegate 委派型別 7.6 結構與類別的關係 7.7 List 泛型類別 7.8 視窗應用程式
3
7.1 繼承 (Inheritance) 7.1.1 類別繼承 物件導向程式設計中的繼承類似真實世界的遺傳
類別繼承 物件導向程式設計中的繼承類似真實世界的遺傳 如兒子遺傳爸媽的特色(屬性或方法),且再擁有 自己新的特色。 透過繼承機制可讓新的類別可延伸出更強功能 將被繼承的類別稱為基底類別(Base class)、父類別 (Parent class)或超類別(Super class), 繼承的類別稱為衍生類別(Derived class)、子類別 (Child class)或次類別(Sub class)
4
類別繼承 Continue… 當子類別繼承自父類別後,子類別擁有父類別 所有的成員(屬性、方法、欄位)。 繼承語法:
6
7.1.2 類別成員的存取限制 類別的成員存取修飾詞三個常用修飾詞說明:
類別成員的存取限制 類別的成員存取修飾詞三個常用修飾詞說明: 1. public public 成員的存取沒有限制,允許在類別、 子類別或宣告的物件中使用public成員, 是屬公開層級。 2. private private成員只能在自身類別內做存取的動作 是屬私有層級,外界無法使用。 3. protected protected成員除可讓自身類別存取外,也可 讓子類別做存取,是屬保護層級。
7
【範例】 定義 Employee 員工類別含有 Salary 薪資屬性, 屬性值設定介於 20,000~40,000 元間;
定義一個繼承自 Employee員工類別的 Manager 經理類別 並在經理類別中新增一個Bonus獎金屬性以及 顯示實領薪資的 ShowTotal()方法。 Manager 經理類別繼承自Employee員工類別 Manager 類別擁有 Employee類別所有成員 (屬性及方法),因此Manager類別也可用 Salary 屬性。 FileName : ConsoleInherits1.sln
8
輸出結果
9
7.2 靜態成員(Static Members) 7.2.1 靜態成員的使用
靜態成員的使用 類別的存取修飾詞:private、protected、public, 還可用 static 來宣告 靜態成員。 使用 static 宣告出的成員 不需經 new 敘述來建立物件實體可直接透過 類別來使用。 static 成員在記憶體中 只儲存一份 且類別所產生的物件都可一起共用此 static 成員
10
【範例】FileName : ConsoleStaticMember.sln
在 Car 類別中宣告 Total 靜態屬性 用來記錄車子物件的總數 當建立 Car 物件執行建構式時, Total 馬上加上1; 在 Car 類別內定義名稱為ShowTotalCars()靜態方法 用來顯示目前共產生幾部車子。 呼叫此方法可直接用 Car. ShowTotalCars() 不用建立 Car物件。
11
輸出結果
12
NET Framework 的記憶體配置
13
關於記憶體回收時機如下: 1. 程式結束時。 2. 記憶體不足時。 3. 執行 GC.Gollect() 時。
14
7.3 多型 (Polymorphism) 多型又稱同名異式 它是透過動態繫結方式讓您在程式執行時可 動態決定物件參考所要執行的方法。
它是透過動態繫結方式讓您在程式執行時可 動態決定物件參考所要執行的方法。 多型允許在程式中使用名稱相同的方法或屬性 不需考慮當時用的物件型別是什麼。 要設計多型 子類別必須先覆寫父類別同名稱的方法或屬性 再使用父類別的物件參考來選擇所要執行 子類別物件實體的方法。
15
7.3 多型 (Polymorphism) Continue …
由於多型會在類別中建立名稱相同的成員 (屬性或方法) 多載 和 覆寫也可建立名稱相同的成員 多載成員 可接受不同個數的參數或不同資料型別的參數, 用來提供不同版本的屬性或方法。 覆寫成員 子類別的成員可用來取代父類別中不適用的成員, 子類別覆寫父類別的成員時,子類別與父類別的 成員必須接受相同個數參數與相同資料型別。
16
子類別想重新定義父類別的方法或屬性(覆寫)
首先必須將父類別的方法或屬性宣告為 virtual 表示父類別允許被子類別同名的方法覆蓋 子類別要覆蓋父類別同名稱的方法 必須將子類別的方法或屬性宣告為 override(覆寫) 表示要重新定義父類別的方法。
17
【範例】FileName : ConsolePolymorphism1.sln
一般而言員工和經理的底薪一定不相同。 Employee員工類別的 Salary 屬性 宣告為virtual 可被覆寫,且員工 Salary 薪水屬性 介於 20,000 ~ 40,000元間; Manager 經理類別的 Salary 薪水屬性宣告為 override 來覆寫父類別的 Salary屬性,且重新定義Manager 經理類別的 Salary 薪水屬性介於 30,000~60,000元。 參閱 P7-9頁
18
子類別如何存取父類別的方法或屬性 如子類別只是要加強父類別方法 在子類別方法中並不需再重新撰寫和父類別 方法中相同的程式 只要在子類別的方法中呼叫父類別的方法 在子類別方法內加上新的功能即可。 在 C# 可用 base 關鍵字來呼叫父類別的屬性或方法 寫法:
19
【範例】 FileName: ConsolePolymorphism2.sln
Employee 父類別的 ShowTotal()方法會顯示底薪, 而 Manager子類別的 ShowTotal() 方法除要顯示 底薪外,還必須顯示(薪水+獎金)的總額。 在 Manager 類別 ShowTotal() 方法中 需用 base.ShowTotal呼叫Employee 的 ShowTotal() 方法。 再加要顯示 (薪水+獎金) 的程式敘述。 參閱 P7-12頁
21
7.3.3 動態繫結 一般程式編譯階段時,物件參考即會決定自己 要執行的方法。
動態繫結 一般程式編譯階段時,物件參考即會決定自己 要執行的方法。 動態繫結(Dynamic Binding) 是程式進入執行階段時,物件參考才決定所要 執行的方法 做法是用父類別的物件參考來選擇所要執行 子類別物件實體的方法,透過這種技巧才可 做到真正的多型。
22
【範例】 FileName: ConsolePolymorphism3.sln
模擬可選擇駕駛車子或飛機共前進幾公里。 範例中 Traffic 交通工具類別中包含: _miles :共用成員用來記錄已前進的公里數 空的SpeedUp()加速方法 子類別 Car 和Airplane 類別分別繼承 Traffic 覆寫 Traffic 父類別 SpeedUp()方法 Car 類別的 SpeedUp()方法每次加速前進2公里; Airplane 類別的 SpeedUp()方法每次加速前進15公里。 參閱 P7-15頁
23
抽象類別 什麼是抽象類別呢?它無法使用new關鍵字來建立實體物件, 抽象類別可定義抽象方法或存取子,最常應用的地方就是抽 象類別中的某些功能可以繼承給子類別(衍生類別),然後再 由子類別對所繼承的抽象類別中的抽象方法或存取子進行實 作,若要宣告抽象類別、抽象方法可以使用abstract 修飾詞。 若使用 abstract 修飾詞宣告方法或屬性,即表示此方法或屬 性並沒有包含實作的部分。例如:以下敘述的Answer方法沒 有程式主體,只有方法宣告及「( )」和「;」一行敘述結束 而己。 public abstract void Answer(); 使用abstract來定義抽象類別及抽象方法,而抽象方法不包含 實作程式碼,因此必須在繼承的子類別中以override(覆寫)修 飾詞定義新的方法功能。接著我們來看看下面兩個範例,練 習如何使用抽象類別:
24
多型 - 範例1 建立一個專案名稱為「WinFormPolymorphism4」的 Windows Form應用程式,並將所有類別定義全部放 在獨立的 Class1.cs 類別檔中,操作步驟:
25
輸出入介面 參閱 P7-22頁
27
輸出入介面 參閱 P7-25頁
28
7.4 介面與實作 C# 所提供的繼承機制只能單一繼承某個父類別, 未提供多重繼承,解決方案透過「介面」解決。
在物件導向技術中,介面比類別還抽象。 可經繼承機制,使子類別能用 override 方式來修改 父類別中事先定義好的成員。 新增所需的功能,也能透過類似 base.方法()方式 來使用父類別原有的成員, 進而使用多型的機制。 介面是物件的某些操作集合。 介面的使用焦點是放在操作物件事上 類別繼承是將焦點放在屬性與方法的重覆使用上。
29
7.4 介面與實作 在物件導向程式設計中,物件可以具有多種型別, 要使物件具有多種型別可以透過繼承來達成。例如 Car物件就同時具有Car(車子)和Traffic(交通工具)兩 種資料型別(類別)。由於C# 只能使用單一繼承的方 式,假若Car類別本身具有SpeedUp(加速)功能,也 希望能像Bird(鳥)類別擁有Fly(飛)的功能的話,因為 Car與Bird這兩種不相關的型別,就無法使用繼承方 式來加強類別的功能。
30
一. 如何使用介面 C# 可用介面來解決上面的問題 介面和類別很像,類別可定義屬性、方法和事件
介面和類別不同的是,介面只宣告方法、屬性和 事件成員,且介面所宣告的成員皆會自動成為 public公開成員。 介面主要用來宣告一組可操作的方法,它就代表一 種方法的合約,當類別實作某介面後,該介面所宣 告的方法要在類別重新實作過。
31
介面語法:
33
【範例】 FileName: ConsoleInterface1.sln
在 Car 類別具有 SpeedUp() 加速方法, Bird 類別具有 Eat() 吃的方法。 若希望 Car 類別和 Bird 類別同時擁有Fly()飛的方法 定義 IFly介面內宣告 Fly() 方法,一旦 Car 類別和 Bird 類別實作 IFly 介面的 Fly() 方法,此時 Car 類別和 Bird 類別的物件即可呼叫 Fly() 方法。 參閱 P7-29頁
36
輸出入介面 程式碼 ConsoleInterface2.sln 參閱 P7-31頁
37
三. 如何使用介面 – 模擬System.Array 類別
上一範例中 執行Array.Sort(vecArray) 時 Sort方法可呼叫 vecArray 陣列中每個元素的 CompareTo方法 進行元素大小比較,進行排序。 在 Sort方法中究竟是如何做的呢? 為深入了解介面的定義方式,來模擬 System.Array 物件中有關 Sort方法的技術。
38
【範例】FileName: ConsoleInterface3.sln
定義一個 IMyComparable 介面 介面中只有一個 方 法 MyCompareTo。規格和 IComparable介面 的CompareTo方法一樣。 比照 Array 類別定義一個 MyArray類別,類別中 只有一個 static 方法 MySort。 在 MySort 中使用最簡單汽泡排序法來對參數 obj 陣列進行排序,比較陣列元素大小時,直接呼叫 MyCompareTo方法來做比較。因此要做為 MySort 方法參數的 obj 物件 (Vector類別)一定要事先實作 出 IMyComparable 介面的 MyCompareTo方法才 可以。
39
輸出入介面設計 參閱 P7-34頁
40
7.5 delegate 委派型別 委派(delegate)是用來儲存方法位址的資料型別。 資料型別可用來宣告變數或物件。
例 int 型別宣告出的變數可儲存數字、 string 型別宣告出的變數可儲存文字。 委派是一種資料型別,只是這種資料型別宣告出 的變數所儲存的是方法的位址。 一個儲存方法位址的委派變數,可用來呼叫該 位址的方法 由於委派變數的內容可動態改變,因此只要將 該變數內容改變為另一個方法的位址,該委派 變數呼叫的就會是另一個方法。
41
7.5 delegate 委派型別 Continue…
在定義物件的事件時,由於無法預期未來使用 這個物件事件的事件處理函式(即方法)的位址。 此在物件中就必須用委派來宣告事件委派變數, 以便可動態將事件委派變數指向事件處理函式 物件就可動態使用事件的委派變數來呼叫外部 的事件處理函式。 結論 :方法(函式) 也可當做一種型別。
42
7.5 delegate 委派型別 Continue…
例如在陣列排序中,如希望 MySort 方法排序方式 可由大排到小,也可由小排到大。 在 MySort 方法中多加一個參數 CompareMethod, 指明比較陣列元素大小的方法。 由於 CompareMethod 參數的型別是一種方法, 這時就可用 delegate 來定義方法的型別 (參數個數 、參數順序、傳回值型別) 首先必須先用 delegate 敘述定義出方法的格式 與委派型別名稱為 CompareFunc。
45
程式碼 : ConsoleDelegate1.sln 參閱 P7-38頁
46
7.6 結構與類別的關係 結構是一種型別,除不支援繼承外, C# 的結構 和類別相似。 結構是實值型別 ,它可比類別更快速地建立。
7.6 結構與類別的關係 結構是一種型別,除不支援繼承外, C# 的結構 和類別相似。 結構是實值型別 ,它可比類別更快速地建立。 若具有大量資料結構在其中建立的緊密迴圈, 就應考慮用結構而不是類別。 類別可視為結構的延伸。 傳統C 的結構只能有資料項目(或稱欄位) 。 C++或 C# 的類別是由資料成員和成員函式組成。
47
7.6 結構與類別的關係 Continue… 類別的資料成員 是由多個資料項目所構成,相當於結構的欄位, 用來代表這個物件的性質或稱屬性。
類別的資料成員 是由多個資料項目所構成,相當於結構的欄位, 用來代表這個物件的性質或稱屬性。 類別的成員函式(或稱方法) 是由函式所組成的,一個函式相當於一種物件 本身的行為或方法,用來處理由外界送進的訊息 加以處理並回應之。 結構就是類別的一個特例。
48
結構和類別差異: 結構宣告內不能初始化欄位, 除非將其宣告為 const 或 static。 結構不可宣告為預設建構函式或解構函式。
結構無法繼承自類別或其他結構。 結構是在指派時複製的。 當指派結構給新變數時,就會複製所有資料, 而新變數所做的任何修改都不會變更原始複本 的資料。 結構為實值型別,而類別則是參考型別。 與類別不同的是,結構不需使用 new 運算子 就能執行個體化。
49
結構和類別差異: 結構可以宣告含有參數的建構函式。
結構無法從另一個結構或類別繼承而來,且 它不能成為類別的基底。所有結構都是由 System.Object 的 System.ValueType 直接繼承 而來。 結構可實作介面。 結構可以用來當做可為 Null 的型別,而且可 以對其指派 null 值。
50
7.7 List 泛型類別 集合物件相當於一個物件的容器,它可用來處理 不定數量的資料,是物件導向程式的資料結構。
集合物件相當於一個物件的容器,它可用來處理 不定數量的資料,是物件導向程式的資料結構。 集合物件是一組相關物件的集合,可將這組物件 的集合視為單一物件。將集合物件內的物件稱為 元素。 集合物件有很多種,儲存的元素允許重複, 有些集合物件的元素自動會進行排序。 主要集合物件:有Collection、List、Set、Map 實作 List 介面的集合物件可擁有重複元素,元素 是以循序方式存入,即以類似陣列索引方式來 存取元素。
51
7.7 List 泛型類別 在 .NET Framework 的 System.Collections.Generic 命名空間內建許多泛型類別可讓開發人員處理各種 資料型別的集合物件 常用泛型類別:List、Queue、Stack…等類別。 List物件主要用來存放串列的資料,串列可動態 新增或刪除,使用上比陣列更具有彈性。語法:
54
【範例】 FileName: ConsoleGenerics1.sln
建立 listInt 和 listMember串列物件 - listInt串列物件依序放入123、789整數資料 - 再 listInt串列 索引1 位置放入 最後印出 listInt 內所有元素。 listMember串列物件可存放 Member 物件 - 先在 listMember內放入三筆Member物件 - 接著刪除索引1 位置的 Member 物件 - 最後再印出 listMember內所有元素。 觀察 listInt 和 listMember串列物件所有元素
55
7.8 視窗應用程式 參閱 P7-44頁
56
本章結束 …
Similar presentations