1.11k likes | 1.35k Views
物件的多重身份- 繼承與多型. 7.1 繼承- Inheritance. 類別與類別之間是可以繼承的,繼承的目的除了讓新開發的類別得以延用即有類別的功能外,更深一層的目的就是表示類別的結構。. 7.1 繼承- Inheritance. 將軍需能夠掃射的重坦克!如何快速的改裝新的重坦克呢?!
E N D
7.1繼承-Inheritance • 類別與類別之間是可以繼承的,繼承的目的除了讓新開發的類別得以延用即有類別的功能外,更深一層的目的就是表示類別的結構。 掌握 C# 4.0 設計概要
7.1繼承-Inheritance • 將軍需能夠掃射的重坦克!如何快速的改裝新的重坦克呢?! • 定義坦克(Tank)類別的目的就是要描述什麼是坦克,而哪些資訊與行為是這個坦克所擁有的(即是欄位、特性與方法)。現在將軍需要一台重坦克(HeavyTank),上面有一座機槍可以進行掃射,此時只要將原本的坦克改裝一下,上面裝座機槍,這樣就變成將軍要的重坦克了,如此就可以進行掃射的能力了。重坦克除了多了一座機槍(MachineGun),並可進行掃射(Rake())外,其實重坦克就像一般的坦克一樣,同樣會有編號(ID)與健康值(HP)等特性,當然也會有射擊方法(Fire)以射擊坦克。為了讓重坦克擁有坦克的資訊與行為,不就要把坦克類別中的程式碼拷貝並重貼到新的重坦克類別中嗎?但更糟的是若沒有原始碼呢?那不就拷貝不到坦克類別中的程式。 掌握 C# 4.0 設計概要
7.1繼承-Inheritance • C7_1_1 HeaveryTank.cs class HeaveyTank : Tank { } 重坦克的英文是HeaveyTank。 冒號(:)讓重坦克(HeaveyTank)繼承自坦克(Tank)。 冒號(:)後面接的就是要被重坦克繼承的坦克類別。 重坦克也是類別,因此也會有一對大括號({ })讓重坦克類別可以裝欄位、特性與方法。 • 這樣就完成了繼承的關係。嗯?!忘了坦克類 別長什麼樣子了嗎?沒關係,我們目前所使用的坦克類別就列在下方: 掌握 C# 4.0 設計概要
7.1繼承-Inheritance • C7_1_1 Tank.cs class Tank { private string id; private int hp = 1000; public String ID { get{return id;} set{id=value;} } public int HP { get{ return hp;} private set { if(value < 0) hp = 0; else hp = value; } } 健康值欄位(hp)的預設值為1000。如此每台坦克的健康值即是1000。 這是編號特性(HP)。 這是健康值特性(HP)。 健康值特性(HP)的在設值存取子中加上了健康值最小為0的限制。 掌握 C# 4.0 設計概要
7.1繼承-Inheritance } public void Show() { Console.WriteLine("編號:"+ id); Console.WriteLine("健康值:"+ hp); } public void Fire(Tank target) { Console.WriteLine("射擊~~~"); Bomb b = new Bomb(); target.BeHit(b); } public void BeHit(Bomb b) { HP = HP - b.Firepower; } } 顯示坦克狀態的方法-顯示狀態方法(Show())。 這是坦克的射擊方法(Fire())。 射擊方法改成射出一個飛彈至目標紙上。模擬的方式就是產生一個飛彈,並轉給目標的被擊中(BeHit())方法,表示飛彈以擊中目標坦克。 被擊中方法(BeHit()),以模擬坦克被飛彈擊中的狀況。 掌握 C# 4.0 設計概要
7.1繼承-Inheritance • C7_1_1 Bomb.cs class Bomb { public int Firepower { get{return 300;} } } Bomb就是飛彈類別。它只有一個火力特性(Firepower)以表示這顆飛彈的威力。 固定每顆飛彈的威力就是300。 掌握 C# 4.0 設計概要
7.1繼承-Inheritance • 繼承讓重坦克擁有坦克的欄位與方法。 • 讓重坦克(HeavyTank)繼承坦克(Tank)的目的,就是讓重坦克類別直接擁有坦克類別即有的功能,像是編號特性(ID)、健康值特性(HP),與顯示狀態方法(Show())和射擊方法(Fire())都可以一次性的擁有下來。現在我們來測試一下重坦克從類別繼承下來的特性與方法。 掌握 C# 4.0 設計概要
7.1繼承-Inheritance • C7_1_1 Program.cs class Program { static void Main(string[] args) { HeaveyTank h1 = new HeaveyTank(); h1.ID = "H001"; HeaveyTank h2 = new HeaveyTank(); h2.ID = "H002"; h1.Show(); h1.Fire(h2); Console.WriteLine(h2.ID); Console.WriteLine(h2.HP); } } 建立重坦克物件(HeavyTank) 這些特性與方法並沒有在重坦克類別中描述,但因為重坦克繼承自坦克(Tank)的關係,所以坦克所有的能力都將會被繼承下來。 掌握 C# 4.0 設計概要
7.1繼承-Inheritance • 重坦克繼承坦克,即產生子類別與父類別的關係。 • 重坦克(HeavyTank)因為繼承的關係,可以直接得到坦克(Tank)的所有特性與方法。而在繼承的關係下,又可分為繼承者與被繼承者的關係;繼承者-重坦克稱為子類別(Sub class ),而被繼承者-坦克稱為父類別(Super class )。這聽起來蠻合理的,就像兒子繼承父親的能力,父親將能力傳給兒子是相同的感覺。在本頁,同時也將介紹統一塑模語言-UML(Unified Modeling Language)來描述類別的結構與關係,而UML是廣泛應用在業界,以圖形描述物件導向程式的一種語言。 掌握 C# 4.0 設計概要
7.1繼承-Inheritance class HeavyTank : Tank { } 繼承者-重坦克(HeavyTank),可稱為是子類別。 被繼承者-坦克(Tank),可稱為是父類別。 最上方是類別的名稱 第2格是用來表示此類別所擁有的特性(註:因C#基本上不以欄位對外開放存取,因此在這所指的即是特性)。 這是UML (Unified Modeling Language,一種業界廣為應用的物件導向程式的圖形描述)用來表示類別的方式。主要是以方形來表示類別。其中可分為三個區塊,由上而下分別為:類別名稱、特性與方法。 第3格是用來表示此類別所擁有的方法。 這個單箭頭的連結線表示繼承的意思。有箭頭的那一端連結著父類別,而無箭頭的則是連結子類別。 因為單箭頭連結線表示重坦克類別(Heavy Tank)將繼承自坦克(Tank)類別,同時亦可稱重坦克類別為子類別。 掌握 C# 4.0 設計概要
7.1繼承-Inheritance • 重坦克可以安裝機槍,並提供掃射的功能嗎? • 重坦克(HeavyTank)成功的以繼承的方式,將坦克(Tank)所有的特性與方法繼承下來,嗯,這是很理想的。但若想要改良重坦克,讓重坦克可以安裝機槍(Has Machine Gun),並進行掃射(Rake())的功能,是不是在繼承之後還是可以加上一些專屬於重坦克的東西呢?! 掌握 C# 4.0 設計概要
7.1繼承-Inheritance • 我們也可以為重坦克加上「是否安裝機槍特性」與「掃射方法」。 • 重坦克(HeavyTank)除了繼承了坦克(Tank)的欄位、特性與方法外,也應該含有重坦克專屬的資訊與行為。雖然重坦克繼承自坦克,但重坦克還是有一些專屬的資訊與行為;如重坦克的「是否安裝機槍」(HasMachineGun)的資訊,還有若有安裝機槍,就可以進行掃射(Rake())的行為。現在讓我們來為重坦克加入專屬的資訊與行為: 掌握 C# 4.0 設計概要
7.1繼承-Inheritance • C7_1_2 HeavyTank.cs class HeavyTank : Tank { private bool hasMachineGun; public bool HasMachineGun { get{return hasMachineGun;} set{ hasMachineGun=value;} } public void Rake() { if(hasMachineGun == true) Console.WriteLine("掃射~~~~"); else Console.WriteLine("機槍還沒安裝..."); } } 為重坦克(HeavyTank)加上是否安裝機槍(hasMachineGun)的欄位。 提供是否安裝機槍特性(HasMachineGun)來存取是否安裝機槍欄位,並達到封裝的效果。 Rake()方法是代表重坦克掃射行為的方法。 當有安裝機槍的時候(也就是hasMachineGun等於true),則進行掃射。 只要直接在重坦克類別中宣告欄位、特性與方法,這樣就可以為重坦克設定專屬的資訊與行為。 這是未安裝機槍的時候(也就是hasMachineGun等於false)顯示的訊息。 掌握 C# 4.0 設計概要
7.1繼承-Inheritance • 測試一下重坦克專屬的是否安裝機槍特性與掃射方法。 • 嗯?!好像少測試欄位了,你沒有看錯這個標題,我們的欄位都是私有化的,唯有坦克物件才可以使用,所以我們將忽略坦克的欄位測試。現在就讓我們來測試重坦克專有的特性與方法: 掌握 C# 4.0 設計概要
7.1繼承-Inheritance • C7_1_2 Program.cs class Program { static void Main(string[] args) { HeavyTank h = new HeavyTank(); h.ID = "H001"; h.Show(); h.HasMachineGun = true; h.Rake(); } } 繼承自坦克類別(Tank)的特性與方法還是可以使用的。 新宣告的特性與方法,在重坦克物件(HeavyTank)上是可以使用的。 執行結果: 編號:H001 健康值:1000 掃射 掌握 C# 4.0 設計概要
7.1繼承-Inheritance • 注意!加在重坦克上的欄位、特性與方法,是不會加在坦克上的。 • 我們為重坦克(HeavyTank)加上的欄位、特性與方法是專屬於重坦克的,並不會同時附加在父類別-坦克(Tank)上。現在就讓我們作個錯誤的示範: 掌握 C# 4.0 設計概要
7.1繼承-Inheritance • C7_1_3 Program.cs class Program { static void Main(string[] args) { Tank t= new Tank(); t.ID = "T001"; t.Show(); t.HasMachineGun =true; t.Rake(); } } 建立的是坦克物件(Tank),而不是重坦克的物件(HeavyTank)。 父類別-坦克原有的特性與方法,並不會因為子類別-重坦克加上新的特性與方法,而有所改變。 千萬別在坦克物件上使用重坦克的特性與方法。這是行不通的,這些特性與方法是專屬於重坦克的。若是執意這麼作,編譯器會發生錯誤,告訴您坦克型別(Tank)的物件並不包含是否安裝機槍特性(HasMachineGun)與掃射方法(Rake) 錯誤訊息列會顯示出錯誤訊息: 掌握 C# 4.0 設計概要
7.1繼承-Inheritance • 注意!坦克的私有化欄位,並不會因繼承而被重坦克發現。 • 坦克類別上的所有欄位,其實皆已經使用private關鍵字進行私有化,私有化後的欄位是不可以被繼承的。這個就好像一件密秘是會永遠埋藏在心中,即使是親如兒子也是一樣不被告知。因此若使用重坦克類別(HeavyTank)強行的存取坦克(Tank)私有化的欄位時,就會發生編譯錯誤: 掌握 C# 4.0 設計概要
7.1繼承-Inheritance • C7_1_4 Program.cs class HeavyTank : Tank { //略過一些程式 public void TryToGetSecret() { Console.WriteLine(id); Console.WriteLine(hp); } } 刻意在重坦克類別(HeavyTank)上加上一個方法,企圖直接取得坦克類別(Tank)所定義的編號(id)與健康值(hp)欄位中的資料。 繼承並不會同時將私有化的欄位也繼承下來。私有於坦克的欄位將永遠私有於坦克,即使在重坦克類別上建立一個方法,直接在類別中使用私有化的欄位也是一樣不可行的,這就像秘密永遠就是秘密。在編譯時錯誤訊息告訴我們編號與健康值欄位目前的存取等級是沒有開放存取的。 編譯時會發生錯誤: 小提示 不論是欄位、特性與方法,只要是經過私有化, 就不會被繼承。 掌握 C# 4.0 設計概要
7.2改寫-Overriding • 子類別繼承自父類別時發現繼承的方法,執行起來並不能滿足子類別所要求的功能時,這時就可以使用改寫的技巧將方法中的程式內容重寫一次,以滿足子類別所要求的功能。 掌握 C# 4.0 設計概要
7.2改寫-Overriding • 如何以重坦克的身份進行顯示狀態?! • 目前坦克(Tank)的顯示狀態方法(Show()),在執行的時候會顯示出坦克的編號(ID)、健康值(HP);但現在重坦克(HeavyTank)繼承了坦克,在進行顯示狀態的同時,除了將坦克的一些基本資訊顯示出來外,還需要加上重坦克特有的資訊,例如是否安裝機槍(HasMachineGun)的資訊,那這時怎麼辦呢?顯示狀態方法又是從坦克繼承下來的?!若想要變更顯示狀態方法中的程式內容, 這該如何辦到?這是有可能的嗎? 掌握 C# 4.0 設計概要
7.2改寫-Overriding • C7_2_1 Program.cs class Program { static void Main(string[] args) { HeavyTank h = new HeavyTank(); h.ID = "H001"; h.HasMachineGun = true; h.Show(); } } 建立重坦克型別(HeavyTank)的物件。 同時,也設定了這台重坦克上的是否安裝機槍特性(HasMachineGun)的值為true。 但因為重坦克的顯示狀態方法(Show())是繼承自坦克類別(Tank)的,因此並不會將是否安裝機槍特性的資訊顯示出來。 執行結果: 編號:H001 健康值:1000 掌握 C# 4.0 設計概要
7.2改寫-Overriding • 改寫方法,讓重坦克以重坦克的身份進行顯示狀態。 • 因為坦克(Tank)的顯示狀態(Show())方法不再適用於重坦克(HeavyTank)身上,因此我們必須將繼承自坦克的顯示狀態方法重新寫過一次,並將方法中的內容重新以新的程式覆蓋過去,而這個動作就稱為改寫-Overriding。為了要進行方法的改寫,必須有兩項工作是必須作的,第1項就是在父類別-坦克類別上使用virtual關鍵字將顯示狀態方法加註為虛擬的;第2項就是子類別-重坦克類別上使用關鍵字override將顯示狀態改寫掉,這樣就完成整個改寫的工作了。 掌握 C# 4.0 設計概要
7.2改寫-Overriding • C7_2_2 Tank.cs 將坦克類別(Tank)上的顯示狀態方法(Show()),在public與void回傳型別之間加上一個關鍵字-virtual,virtual的意思就是「虛擬的」意思,即有可以被改變的意思。 class Tank { //略過一些程式 public virtual void Show() { Console.WriteLine("編號:"+ id); Console.WriteLine ("健康值:"+hp); } } UML習慣將改寫的方法再一次的寫出來,表示這個方法進行了改寫的動作。就像顯示狀態方法(Show())在子類別-重坦克類別中再出現一次,即表示改寫的意思。 掌握 C# 4.0 設計概要
7.2改寫-Overriding • C7_2_2 HeavyTank.cs 在public與void關鍵字之間加上一個關鍵字-override,override的意思就是「改寫的」意思,在此將進行顯示狀態方法的改寫。特別記得,只有繼承的方法才有改寫的機會。 class HeavyTank : Tank { //略過一些程式 public override void Show() { Console.WriteLine("這是一台重坦克"); Console.WriteLine("編號:"+ ID); Console.WriteLine("健康值:"+HP); Console.WriteLine("是否安裝機槍:"+ HasMachineGun); } } 改寫主要改變的是方法內容的部份。現在將原本重坦克資訊缺少的部份補上,好讓重坦克可以重坦克的身份進行顯示狀態的行為。 掌握 C# 4.0 設計概要
7.2改寫-Overriding • 測試重坦克的顯示狀態方法... • 顯示狀態方法(Show())在重坦克類別(HeavyTank)中已經重新定義過了,除了列出坦克的資訊外,還會列出專屬於重坦克的資訊。現在就讓我們來測試一下: 掌握 C# 4.0 設計概要
7.2改寫-Overriding • C7_2_2 Tank.cs class Program { static void Main(string[] args) { HeavyTank h = new HeavyTank(); h.ID = "H001"; h.HasMachineGun = true; h.Show(); } } 建立重坦克物件(HeavyTank)。 現在是以一個重坦克的身份進行顯示狀態的行為(Show())。很好~~多了重坦克特有的資訊-是否安裝機槍(HasMachineGun)。這就是重坦克改寫顯示狀態方法後,即可以使用重坦克版本的顯示狀態方法,進行坦克狀態的顯示。 執行結果: 這是一台重坦克 編號:H001 健康值:1000 是否安裝機槍:true 掌握 C# 4.0 設計概要
7.2改寫-Overriding • 改寫重坦克的方法,並不會改變坦克原有的方法。 • 改寫是發生在繼承的情況下,而且改寫的對象必須是方法,此方法必須是父類別即有的方法。如此的情況下,才能在子類別再一次的重新定義此方法,以進行方法的改寫。就像是重坦克(HeavyTank)繼承自坦克(Tank)一樣,重坦克將繼承下來的顯示狀態方法(Show())重新進行改寫,但改寫的同時,並不會改變坦克原本的顯示狀態方法中的程式內容。 掌握 C# 4.0 設計概要
7.2改寫-Overriding • C7_2_3 Tank.cs class Program { static void Main(string[] args) { Tank t = new Tank(); t.ID = "T001"; t.Show(); HeavyTank h = new HeavyTank(); h.ID = "H002"; h.HasMachineGun=true; h.Show(); } } 坦克(Tank)並不會因為重坦克對顯示狀態(Show())的改寫而有所改變,它還是會以坦克原本的顯示狀態方法進行坦克狀態的顯示。 執行結果: 編號:T001 健康值:1000 這是一台重坦克 編號:H002 健康值:1000 是否有機槍:true 重坦克(HeavyTank)會以重坦克的身份進行顯示狀態,即呼叫改寫後的顯示狀態方法。 小提示 當然,特性也是可以改寫的,但記住,請先為特性加 上virtual,如此子類別才可以透過override關鍵字進行 改寫。 掌握 C# 4.0 設計概要
7.2改寫-Overriding • 重坦克可以透過base再次的使用坦克上的顯示狀態方法。 • 我們可以使用base很明確的告知編譯器,說明要使用的方法是位於父類別上的方法。現在就讓我們看看如何透過base使用父類上的方法。如此就可以在重坦克(HeavyTank)改寫顯示狀態方法(Show())時,再一次的使用坦克(Tank())的顯示狀態方法了。 掌握 C# 4.0 設計概要
7.2改寫-Overriding • C7_2_4 HeavyTank.cs class HeavyTank : Tank{ //略去一些欄位、特性與方法 public override void show(){ Console.WriteLine("這是重坦克"); base.Show(); Console.WriteLine("是否安裝機槍:"+hasMachineGun); } } base有基底類別的意思,可作為父類別-坦克類別的代名詞,因為重坦克(HeavyTank)與坦克透過了繼承產生了父子類別的關係。 如此重坦克在改寫顯示狀態方法時,只要另外加上重坦克部份的內容就可以了,即顯示是否安裝機槍欄位(hasMachineGun)的資訊。 透過base使用父類別-坦克類別(Tank)的顯示狀態方法,其會顯示編號(id)與健康值(hp)欄位的資訊。 掌握 C# 4.0 設計概要
7.2改寫-Overriding • 當然,重坦克也可以透過base使用坦克上的所有特性。 • base既是父類別的代名詞,只要是定義在父類別的特性,也是可以被存取的。就像定義在坦克類別(Tank)上的編號(ID)與健康值(HP)特性一樣,一樣可以透過base進行存取。 掌握 C# 4.0 設計概要
7.2改寫-Overriding • C7_2_5 HeavyTank.cs class HeavyTank : Tank{ //略去一些欄位、特性與方法 public override void show(){ Console.WriteLine("這是重坦克"); Console.WriteLine("編號:"+base.ID); Console.WriteLine("健康值:"+base.HP); Console.WriteLine("是否安裝機槍:"+hasMachineGun); } } 雖然可以直接存取繼承坦克類別而來的編號(ID)與健康值(HP)特性,但您還是可以多此一舉的使用base來存取編號與健康值特性。 小提示 其實,base也可以用來存取父類別-坦克類別上的欄位, 只要坦克上的欄位不是私有化的,即可進行存取,換句 話說,只要將坦克類別上的編號(id)與健康值(hp) 欄位改成公開化(使用public修飾),子類別-重坦克即 可透過base進行存取。 掌握 C# 4.0 設計概要
7.3 繼承與保護化-Inheritance & protected • protected關鍵字可以讓欄位、特性或方法進行保護化,亦可透過繼承的方式進行存取;相對的,非繼承的類別將不可存取這些保護化後的欄位、特性與方法。 • 繼承自坦克的重坦克,如何取得真實的健康值? • 現在重新為坦克類別加入新的真實健康值欄位(realHP),並透過被擊中方法(BeHit())真實的計算健康值的數值,即便是負數也是一樣。 掌握 C# 4.0 設計概要
7.3 繼承與保護化-Inheritance & protected • C7_3_1 Tank.cs class Tank { //略過一些程式 private int hp = 1000; private int realHP = 1000; public void BeHit(Bomb b) { HP = HP - b.Firepower; realHP = realHP - b.Firepower; } } 健康值欄位(hp)還是一樣是私有化的。 現在多一個真實健康值欄位(realHP)來保存真實的健康值的數值。 坦克被擊中(BeHit())時,會真實的計算真實健康值欄位(realHP)的數值,即便是負數也是一樣。 掌握 C# 4.0 設計概要
7.3 繼承與保護化-Inheritance & protected • C7_3_1 HeavyTank.cs class HeavyTank : Tank { //略過一些程式 public override void Show() { Console.WriteLine("這是一台重坦克"); Console.WriteLine("編號:"+ ID); Console.WriteLine ("健康值:"+HP); Console.WriteLine ("是否安裝機槍:"+ HasMachineGun); } } 因為健康值特性(HP)上的取值存取子的關係,即使在射擊(Fire())的時候能夠真實的將健康值反應在真實健康值欄位上(readHP),但重坦克(HeavyTank)還是只能夠透過健康值特性(HP)取得最小值為0的健康值。 掌握 C# 4.0 設計概要
7.3 繼承與保護化-Inheritance & protected • C7_3_1 Program.cs class Program { static void Main(string[] args) { Tank h1 = new Tank(); h1.ID = "H001"; HeavyTank h2 = new HeavyTank(); h2.ID = "H002"; h2.HasMachineGun=true; h1.Fire(h2); h1.Fire(h2); h1.Fire(h2); h1.Fire(h2); Console.WriteLine(h2.HP); h2.Show(); } } 執行結果: 射擊~~~ 射擊~~~ 射擊~~~ 射擊~~~ 0 這是一台重坦克 編號:H002 健康值:0 是否安裝機槍:True 建立一個重坦克。 即便被射擊了4次,真實健康值欄位(realHP)中的值是-200。 但因為重坦克只能透過繼承的健康值特性(HP)取得健康值,因此取得的最小數值為0。這時要怎麼作才可以讓重坦克也可以取得真實的健康值呢? 掌握 C# 4.0 設計概要
7.3 繼承與保護化-Inheritance & protected • protected讓只有透過繼承的重坦克,存取真實健康值欄位。 • 為了讓重坦克可以取得真實健康值欄位(realHP)中的數值,這時可以使用protected關鍵字,讓真實健康值欄位成為保護化的,保護此欄位除了坦克(Tank)本身可存取外,另外只可以透過繼承的方式,被子類別進行存取。 掌握 C# 4.0 設計概要
7.3 繼承與保護化-Inheritance & protected • C7_3_2 Tank.cs class Tank { //略過一些程式 protected string realHP; } 使用protected關鍵字,將真實健康值欄位(realHP)變成保護化的。 掌握 C# 4.0 設計概要
7.3 繼承與保護化-Inheritance & protected • C7_3_2 HeavyTank.cs class HeavyTank : Tank { //略過一些程式 public void RealShow() { Console.WriteLine("這是一台重坦克"); Console.WriteLine("編號:"+ ID); Console.WriteLine ("健康值:"+realHP); Console.WriteLine ("是否安裝機槍:"+ HasMachineGun); } } 新的真實顯示狀態方法(RealShow())。 因為真實健康值欄位(realHP)是保護化的,因此繼承的重坦克(HeavyTank)類別可以直接存取。記住,類別是為物件所作準備的,因此保護化的欄位也可以說成是物件內部使用的欄位。 掌握 C# 4.0 設計概要
7.3 繼承與保護化-Inheritance & protected • C7_3_2 Program.cs class Program { static void Main(string[] args) { Tank h1 = new Tank(); h1.ID = "H001"; HeavyTank h2 = new HeavyTank(); h2.ID = "H002"; h2.HasMachineGun=true; h1.Fire(h2); h1.Fire(h2); h1.Fire(h2); h1.Fire(h2); h2.RealShow(); } } 建立一個重坦克(HeavyTank)。 執行結果: 射擊~~~ 射擊~~~ 射擊~~~ 射擊~~~ 這是一台重坦克 編號:H002 健康值:-200 是否安裝機槍:True 被射擊了4次,真實健康值欄位(realHP)中的值是-200。 真實顯示狀態方法(RealShow())會直接存取保護化的真實健康值欄位(realHP),因此可以取得真實健康值欄位中真實的數值。 掌握 C# 4.0 設計概要
7.3 繼承與保護化-Inheritance & protected • 當然protected也可以讓坦克的特性與方法,只被繼承的重坦克存取。 • 其實protected也可以讓特性與方法成為保護化的,當然,這些保護化後的特性與方法,也只能透過繼承的方式進行存取。 掌握 C# 4.0 設計概要
7.3 繼承與保護化-Inheritance & protected • C7_3_3 Tank.cs class Tank { //略過一些程式 protected string hp; protected int RealHP { get{return hp;} } protected int GetRealHP() {return hp;} } protected關鍵字也可以使用在特性與方法上。 掌握 C# 4.0 設計概要
7.3 繼承與保護化-Inheritance & protected • C7_3_3 Tank.cs class HeavyTank : Tank { //略過一些程式 public void ShowRealHP1() { Console.WriteLine(RealHP); } public void ShowRealHP2() { Console.WriteLine(GetRealHP()); } } 保護化的特性與方法,也可以被繼承的重坦克類別(HeavyTank)存取。 掌握 C# 4.0 設計概要
7.3 繼承與保護化-Inheritance & protected • 注意,protected是不對外開放的,只可在繼承的重坦克類別中使用。 • protected保護化後的欄位、特性與方法只能被繼承的類別所使用。 掌握 C# 4.0 設計概要
7.3 繼承與保護化-Inheritance & protected • C7_3_4 Tank.cs class Tank{ //略過一些程式 protected int realHP = 1000; protected int RealHP{get{return realHP;} } protected int GetRealHP(){return realHP;} } 這些欄位、特性與方法皆是透過protected關鍵字進行保護化的。 掌握 C# 4.0 設計概要
7.3 繼承與保護化-Inheritance & protected • C7_3_4 Program.cs class Program{ static void Main(string[] args){ HeavyTank h2 = new HeavyTank(); Console.WriteLine(h2.hp); Console.WriteLine(h2.ReadHP); Console.WriteLine(h2.GetRealHP()); } } 即便建立的是一個重坦克(HeavyTank)物件,但因為保護化的欄位、特性與方法,只能限於重坦克類別中使用,因此若透過重坦克物件來存取,將會發生編譯錯誤的狀況。 編譯發生錯誤: 掌握 C# 4.0 設計概要
7.4 多型-Polymorphism • 多型就是指"多種型別的意思",一個物件可以同時擁有一個以上的型別,但前提是要先有繼承。擁有多個型別的物件是可以一再的轉型的,只要是此物件擁有的型別就可以進行轉型的操作;而物件在進行型別轉換後,其型別將決定物件的可操作範圍。 掌握 C# 4.0 設計概要
7.4 多型-Polymorphism • 讓坦克的角色更多樣化。 • 在戰爭的世界上坦克也可分為好幾種,不同的坦克在功能上皆有所差異,造成每個種類的坦克都會擁有各自的欄位、特性與方法。但不論是什麼種類的坦克,坦克終究是坦克,一定會有坦克基本的欄位、特性與方法。因此我們可以使用繼承的方式,產生不同種類的坦克類別,以表示不同種類坦克之間的差異。現在,讓我們加入新的自爆坦克(BoomTank)與兩棲坦克(AmphibiousTank)吧,但首先,我們還是先回顧一下重坦克(HeavyTank)在繼承後的變化: 掌握 C# 4.0 設計概要