[.net 物件導向程式設計基礎] (15) 抽象類
前面我們已經使用到了虛方法(使用 Virtual修飾符)和抽象類及抽象方法(使用abstract修飾符)我們在多型一節中說到要實現類成員的重寫必須定義為一個虛方法或抽象方法。這節單獨把抽象類提出來,是因為抽象是.net實現物件導向程式設計重要的重要思想,定義抽象類就象一個模板一個提綱,它可以理解為中央的指導思想,我們通過派生類去具體實現它。由此可見,抽象類本身沒有任何作用,也不能被例項化,因為他本身就不具有具體的事物。比如上節的動物類的例 子,我們例項化一個動物類並沒有意義,我們需要例項的類是具體的動物,比如Dog、Cat、Sheep這些。
而我們使用物件導向程式設計,就要在具體的應用過程中,學會抽象出事物的共同點,形成一個基類,其它類去繼承他,實現他。為我們提高程式設計、學習設計模式很有益處。
1.什麼是抽象類
如果一個類不與具體的事物相聯絡,而只是表達一種抽象的概念,僅僅是作為其派生類的一個基類,這樣的類就是抽象類,在抽象類中宣告方法時,如果加上abstract時就是抽象方法
1.抽象類的宣告
抽象類使用abstract 關鍵詞進行宣告。
2.抽象類的特點:
A.抽象類不能被例項化
B.抽象類是一種特殊的類,具有類的特性,其成員可以是抽象的,也可以不是抽象的。
C.抽象方法必須定義在抽象類中,而不能定義在非抽象類中
D.抽象類可以繼承一個抽象類,其派生類仍然是一個抽象類
E.抽象類不能被密封(不能使用sealed(sealed指該類不可被繼承))
3.抽象方法的特點:
A.抽象方法是隱式的虛方法
B.抽象方法只允許宣告在抽象類中
C.抽象方法不能提供實際的實現,所以沒有方法體;抽象方法的實現是在非抽象的派生類中以override重寫實現的
D.抽象方法宣告中不可以使用static或者virtual修飾符
E.abstract關鍵字不能修飾靜態方法或靜態屬性
6.抽象類的建構函式
A.不要再抽象類中定義public或protected internal訪問許可權的建構函式
B.應在抽象類中定義protected或private訪問許可權的建構函式
C.如果在抽象類中定義一個protected建構函式,則在例項化派生類時,基類可以執行初始化任務
7.抽象方法和虛方法的區別
虛方法(使用Virtual修飾符)有實現部分,並且派生類對其重寫是可選的;抽象方法沒有實現部分,並且強制非抽象派生類對其重寫
8.抽象類和介面的區別
其實這個區別,本來是要在下一節,介面中講的,在這裡提前說一下,有點印象也好。
A.它們的派生類只能繼承一個基類,即只能繼承一個抽象類,但是可以繼承多個介面。
B.抽象類中可以定義成員的實現,但介面中不可以。
C.抽象類中包含欄位、建構函式、解構函式、靜態成員或常量等,介面中不可以。
D.抽象類中的成員可以私有的(只要不是抽象的)、受保護的、內部的或受保護的內部成員,但介面中的成員必須是公共的。
PS:抽象類和介面這兩種型別用於完全不同的目的。抽象類主要用作物件系列的基類,共享某些主要特性,例如共同的目的和結構。介面則主要用於類,這些類在基礎水平上有所不同,但仍然可以完成某些相同的任務。
7. 舉例
我們舉一個例子來說明一下抽象類的使用,還是我們前面的例子,基類動物(Animal),我們定義成一個抽象類,有幾個派生類狗、貓、羊,假如我們貓還有波斯貓,狗還有牧羊犬,那麼我們還可以讓它們再次繼承,因為貓和狗本身也是動物,我們可以不定義為抽象類,讓他們支援例項化。下面看一下UML圖:
關於UML圖我會在後面抽時間寫的,裡面的成員+表示公有,-表示私有,欄位、屬性、方法使用分割線
下面是具體實現程式碼:
1 /// <summary> 2 /// 動物類(父類 抽象類) 3 /// </summary> 4 abstract class Animal 5 { 6 /// <summary> 7 /// 名字 8 /// 說明:類和子類可訪問 9 /// </summary> 10 protected string name; 11 12 13 /// <summary> 14 /// 建構函式 15 /// </summary> 16 /// <param name="name"></param> 17 public Animal(string name) 18 { 19 this.name = name; 20 } 21 22 private int shoutNum = 3; 23 public int ShoutNum 24 { 25 get { return shoutNum; } 26 set { shoutNum = value; } 27 } 28 29 /// <summary> 30 /// 名字(虛屬性) 31 /// </summary> 32 public virtual string MyName 33 { 34 get { return this.name; } 35 36 } 37 38 /// <summary> 39 /// 叫聲,這個方法去掉虛方法,把迴圈寫在這裡 40 /// </summary> 41 public void Shout() 42 { 43 string result = ""; 44 for (int i = 0; i < ShoutNum; i++) 45 result += getShoutSound()+"!"; 46 47 Console.WriteLine(MyName); 48 Console.WriteLine(result); 49 } 50 51 /// <summary> 52 /// 建立一個叫聲的虛方法,子類重寫 53 /// </summary> 54 /// <returns></returns> 55 public virtual string getShoutSound() 56 { 57 return ""; 58 } 59 60 61 } 62 63 /// <summary> 64 /// 狗(子類) 65 /// </summary> 66 class Dog : Animal 67 { 68 string myName; 69 public Dog(string name) 70 : base(name) 71 { 72 myName = name; 73 } 74 75 /// <summary> 76 /// 名字(重寫父類屬性) 77 /// </summary> 78 public override string MyName 79 { 80 get { return "我是:狗狗,我叫:" + this.name; } 81 } 82 83 /// <summary> 84 /// 叫(重寫父類方法) 85 /// </summary> 86 public override string getShoutSound() 87 { 88 return "汪!"; 89 } 90 } 91 92 /// <summary> 93 /// 狗(子類) 94 /// </summary> 95 class ShepherdDog : Dog 96 { 97 string myName; 98 public ShepherdDog(string name): base(name) 99 { 100 myName = name; 101 } 102 103 /// <summary> 104 /// 名字(重寫父類屬性) 105 /// </summary> 106 public override string MyName 107 { 108 get { return "我是:牧羊犬,我叫:" + this.name; } 109 } 110 111 /// <summary> 112 /// 叫(重寫父類方法) 113 /// </summary> 114 public override string getShoutSound() 115 { 116 return "汪~嗚!"; 117 } 118 } 119 120 /// <summary> 121 /// 貓(子類) 122 /// </summary> 123 class Cat : Animal 124 { 125 string myName; 126 public Cat(string name) 127 : base(name) 128 { 129 myName = name; 130 } 131 /// <summary> 132 /// 名字(重寫父類屬性) 133 /// </summary> 134 public override string MyName 135 { 136 get { return "我是:貓咪,我叫:" + this.name; } 137 138 } 139 140 /// <summary> 141 /// 叫(重寫父類方法) 142 /// </summary> 143 public override string getShoutSound() 144 { 145 return "喵!"; 146 } 147 } 148 149 /// <summary> 150 /// 貓(子類) 151 /// </summary> 152 class PersianCat : Cat 153 { 154 string myName; 155 public PersianCat(string name): base(name) 156 { 157 myName = name; 158 } 159 /// <summary> 160 /// 名字(重寫父類屬性) 161 /// </summary> 162 public override string MyName 163 { 164 get { return "我是:波斯貓,我叫:" + this.name; } 165 166 } 167 168 /// <summary> 169 /// 叫(重寫父類方法) 170 /// </summary> 171 public override string getShoutSound() 172 { 173 return "喵~嗚!"; 174 } 175 } 176 177 178 /// <summary> 179 /// 羊(子類) 180 /// </summary> 181 class Sheep : Animal 182 { 183 string myName; 184 public Sheep(string name) 185 : base(name) 186 { 187 myName = name; 188 } 189 /// <summary> 190 /// 名字(重寫父類屬性) 191 /// </summary> 192 public override string MyName 193 { 194 get { return "我是:羊羊,我叫:" + this.name; } 195 196 } 197 /// <summary> 198 /// 叫(重寫父類方法) 199 /// </summary> 200 public override string getShoutSound() 201 { 202 return "咩!"; 203 } 204 }
呼叫及結果如下:
//呼叫 Animal persianCat = new PersianCat("好貓"); persianCat.Shout(); Console.ReadLine();
//結果如下: //我是:波斯貓,我叫:好貓 //喵~嗚!!喵~嗚!!喵~嗚!!
10要點:
抽象類是指:一個類不與具體的事物相聯絡,而只是表達一種抽象的概念,僅僅是作為其派生類的一個基類。
抽象類是一種特殊類,使用abstract宣告
抽象類不可被例項化
抽象類可以繼承一個抽象類
抽象方法只能存在於抽象類中,可以和虛方法一樣,在派生類中重寫。
抽象類的存在就是被繼承用的,因此不允許被密封(即不能使用sealed修飾)
最後,抽象,是物件導向程式設計的重要思想。。
==============================================================================================
返回目錄
<如果對你有幫助,記得點一下推薦哦,有不明白的地方或寫的不對的地方,請多交流>
==============================================================================================