第十講 介面 繼承與多型
介面
???????介面定義物件成員的合同,是現代元件程式設計不可缺少的一環。c#採用關鍵字「inte***ce」來建立介面。介面作為一種型別,它也具有其他型別所共有的五種訪問修飾和new重定義修飾符。介面可以包含方法,屬性,事件,索引器四種成員,介面本身只能宣告這些成員,不必也不能提供這些成員的具體實現。c#不允許我們為介面成員做任何訪問修飾,介面成員的訪問修飾預設為public——介面本來就是我們為其他型別定義的一種成員合同,對他們進行訪問限制不符合我們應用介面的初衷。同樣的道理,c#也不允許對介面做「abstract, virtual, override, static」修飾。下面是介面型別宣告的乙個典型的例子:
public delegate void stringlistevent(istringlist sender);
public inte***ce istringlist
//唯讀屬性
???event stringlistevent changed;//事件
???string this[int index] //索引器
}?????????
注意這裡我們將介面名稱寫成istringlist,其中的大寫字母「i」僅僅是.***平台的命名約定,而非必須。
???????介面作為一種用於「合同」的型別不可以象類那樣例項化,我們說乙個資料是某個介面型別,我們是指該型別實現了某個介面。c#中類或結構可以實現多個介面,實現了介面的型別必需提供相應介面成員的實現。
inte***ce icloneable
inte***ce i***parable
class listentry: icloneable, i***parable
// icloneable介面實現
???public int ***pareto(object other) // i***parable介面實現
}?????????介面之間可以繼承,乙個介面可以繼承自多個介面。直接或間接繼承自己都會引起編譯時錯誤。下面是乙個介面繼承的例子:
inte***ce icontrol
inte***ce itextbox: icontrol
inte***ce ilistbox: icontrol
inte***ce i***bobox: itextbox, ilistbox {}????
???????通過繼承,介面i***bobox擁有paint,settext,setitems三個方法合同。多介面繼承可能會帶來同名成員衝突的問題,c#通過明晰轉型來解決這個問題。看下面的例子:
inte***ce ilist
}inte***ce icounter
inte***ce ilistcounter: ilist, icounter {}
class c
}???????注意這種明晰轉型是在編譯時進行的,並不會帶來任何程式執行的代價。上面的例子用ilistcounter介面作為方法test的引數型別,但我們知道介面是不可以例項化的型別,我們該怎樣傳遞這樣的引數呢?答案是傳遞直接或間接實現了該介面的類或結構的物件例項。
繼承
???????繼承是物件導向的三大特徵之一(另外兩個是封裝和多型),在元件程式設計中有相當的應用。c#為我們提供兩種繼承機制——類繼承和介面繼承。類繼承只允許每個類有乙個父類(即單繼承),而介面繼承卻允許乙個類或介面可以同時繼承(又稱實現)多個介面。類不可以被介面繼承。
在c#中類繼承是指通過繼承子類將擁有除父類的例項構造器,靜態構造器和析構器以外的所有的成員。注意這裡的「擁有」和「可見性」是兩個概念。擁有某個成員是指該成員確確實實地存在於該類中,但如果該成員的保護級不允許該成員在繼承子類中可見(比如private,internal),我們將不能在子類中對他們進行操作——但這不表示他們不存在。下面的例子清晰地說明了這一點:
class a
????????set
????}
}class b:a
{}class test
}???????count變數在a中為private,在b中不可見,但通過公有屬性count的訪問,我們可以清晰地感覺到它的存在。
子類在繼承的同時可以新增新的類成員。new關鍵字可以使子類在繼承的時候遮蔽同名的父類成員,注意這裡遮蔽的意思同樣是「不可見」,而非「去除」。
我們可以用類修飾關鍵字abstract和sealed來控制類繼承時的行為。abstract使得該類只能被子類繼承,而不能被例項化。sealed不允許該類被繼承,使得繼承樹「到此為止」。
介面繼承由於所有的成員都為public,它的行為比較簡單,僅僅是繼承所有介面的成員。和類繼承相同的地方是new關鍵字同樣可以遮蔽同名成員。
多型
???????多型是指為同名的方法提供不同的實現的能力,它使得我們不用關心方法的具體實現而僅僅依靠其名稱來進行呼叫操作。比如我們現在有乙個road的類需要呼叫drive方法,不管我們有什麼樣的車,bike,car,jeep,儘管他們的drive方式不同,但只要他們有drive方法,我們的road就可以呼叫他們的drive方法使他們在上面「行駛」。多型集中體現了物件世界的共同行為。c#為我們提供了三種多型能力:介面多型,繼承多型,抽象多型。
???????介面定義乙個型別需要實現的方法,屬性,索引和事件,包括可能的引數型別和返回值型別,而把具體的實現交由相應的類或結構來做,從而為元件提供多型能力。介面多型不僅為元件提供乙個更好的邏輯功能的聚合方式,也為元件的多版本提供了很好的支援。隨著元件規模的不斷增長,需要的成員越來越多,將所有的成員簡單地封裝在乙個元件內既不符合我們的邏輯思維方式,更會帶來煩惱的版本問題。而將這些成員分解成多個聚合的邏輯塊,然後採用介面的形勢將他們進行封裝,這種方式很好地解決了元件在設計和維護兩個方面的問題。介面多型在現代軟體開發中有著廣泛的應用。
???????類繼承使得子類自動擁有父類大多數的成員,c#允許我們通過普通的類繼承來為元件提供多型能力。繼承常用於在乙個現有父類的基礎上的功能擴充套件,往往是我們將幾個類中相同的成員提取出來放在父類中實現,然後在各自的子類中加以繼承。「子類 is a 父類,蘋果 is a水果」是繼承多型的經典測試用語。繼承對於小規模的軟體開發多有裨益,但在現代集群元件開發模式下,由於常常引入晦澀的邏輯誤用和不必要的編碼負擔,它往往不被推薦使用。
???????抽象多型是指通過abstract(抽象)類同時實現繼承和介面的多型功能。抽象類中既可以包括實現了的成員,也可以是僅僅提供成員介面而沒有具體實現。抽象類不能被例項化,必須在其繼成類中實現相應的介面,否則子類也應被標誌為abstract。抽象類在為其子類提供乙個恆定的功能集的同時,也為其子類提供了乙個具備擴充套件能力的彈性介面。抽象類在元件的初始設計時非常有用,但由於類不能進行多繼承,它的多型能力較之介面多型要有所損失。
C 銳利體驗 第十六講 對映
c 銳利體驗 南京郵電學院李建忠 lijianzhong 263.第十六講對映 動態型別查詢 我們知道,c 編譯後的 pe檔案主要由 il 和元資料組成,元資料為 元件提供了豐富的自描述特性,它使得我們可以在 執行時獲知元件中的型別等重要的資訊。在 c 中這是通過一種稱作對映 reflection ...
C 銳利體驗 第十七講 異常處理
c 銳利體驗 南京郵電學院李建忠 lijianzhong 263.第十七講異常處理 異常處理 結構化異常處理是現代分布式環境下元件設計的乙個必要的環節,通用語言執行時從底層構造給予異常處理以堅實的支援。在c 中,異常物件被設計為封裝了各種異常資訊的類 system.exception及其繼承子類,和...
C 銳利體驗 第十一講 陣列
第十一講 陣列 陣列 陣列是程式設計常用的一種資料結構。和c c 一樣,c 中的陣列索引從0開始,且其元素型別必須為相同,當然由於多型等帶來的隱式轉型則另當別論。c 中的陣列可以分為一維陣列,多維陣列以及參差陣列 ragged array 它們各自的宣告,初始化,以及元素索引都有不同語法規定。c 同...