子類型

子類型

在程式語言理論中,子類型是一種類型多態的形式。這種形式下,子類型可以替換另一種相關的數據類型(超類型,英語:supertype)。也就是說,針對超類型元素進行操作的子程式、函式等程式元素,也可以操作相應的子類型。如果 S 是 T 的子類型,這種子類型關係通常寫作 S

定義

由於子類型關係的存在,某個對象可能同時屬於多種類型,因此,子類型是一種類型多態的形式,也被稱作 子類型多態(subtype polymorphism)或者 包含多態(inclusion polymorphism)。在面向對象程式設計中,多態一般僅指這裡所說的“子類型多態”,而“參數多態”則一般被稱作泛型程式設計。

子類型與面向對象語言中(類或對象)的繼承是兩個概念。子類型反映了類型(即面向對象中的接口)之間的關係;而繼承反映了一類對象可以從另一類對象創造出來,是語言特性的實現。因此,子類型也稱 接口繼承;繼承稱作 實現繼承

如果一個類型S是另一個類型T的子類型,則對用T表達式的所有程式P,當用S替換程式P中的T時,程式P的功能不變 。

在c++中,以public方式繼承的派生類可看做基類的子類型。

性質

某種程度上來說,類型S與類型T等價。類型S包含T的全部內容,但是類型T不一定包含S的全部內容。對基類所能實施的操作完全適用於派生類(子類型),一個子類型的數據也可以賦值或作為參數傳遞給類型T的變數。具體可總結為一下幾點:

·基類的操作可以實施到派生類對象

·基類指針變數可以指向派生類對象

·派生類對象可以賦值給基類對象

·派生類操作不可以用於基類對象

·派生類指針變數不可以指向基類對象

·基類對象不能賦值給派生類對象

例子

圖一 圖一

右圖中給出了子類型的一個簡單實際例子。一般性對象“鳥”(或超類型)引發了三個派生對象(或子類型)“鴨子”、“杜鵑”和“鴕鳥”。每個都以自己的方式改變了基本的“鳥”的概念,但仍繼承了很多“鳥”的特徵。一個數據對象可以被聲名為這四種類型中任何一個。這個圖中使用了UML符號,箭頭指示方向和超類型和它的子類型之間的聯繫。

在多數基於類的面向對象程式語言中,子類引出子類型:如果 A是 B的子類,則類 A的實例可以用在期望類 B的實例的任何上下文中;所以我們稱 A是 B的子類型。一個結論就是聲明有類型 B的任何變數或形式參數在運行時間可以持有類 A的一個值;在這種情況下很多面向對象編程者會聲稱 B是這個變數的“靜態類型”而 A是它的“動態類型”。這個規則的例外包括C++語言中的私有繼承(它不創建子類型),和Eiffel語言中在派生類型上特定運算,在其中繼承自基類的特徵可以用違反子類型規則的方式去除或修改。

另一個例子是可以允許整數值被用在期望浮點數值的地方,或可以定義包含整數和實數二者的一個類型number的語言。在第一種情況下,整數類型將是浮點數類型的子類型;在第二種情況下,這兩個類型都是number的子類型而相互之間無子類型關係。

編程者可利用子類型來以比沒有它更抽象的方式來寫代碼。考慮下面的例子:

如果整數和實數都是number的子類型,則二者任何類型都可以傳遞給這個函式。為此,子類型經常被認為是一種形式的多態性。上述例子也可以比較於 C++ 語言的模板。

在類型論中,子類型關係經常寫為<:,有著 A<: B意味著 A是 B的子類型。在類型論中子類型可用如下事實來特徵化,如果 A<: B,類型 A的任何表達式也可被給予類型 B;立法這個特徵化的形式類型規則叫做“包容”規則。

子類型方案

類型理論研究者區分兩類類型系統:

•名義子類型,在其中只有類型聲明的名字相同才算是相同類型,子類型關係必須被顯式聲明。C,C++,C#,Java,Objective-C等語言均屬於這類。

•結構子類型,在其中兩種類型的結構組成決定了一種類型是否是另一種類型的子類型。

上面描述的基於類的面向對象子類型描述是名義的;面向對象的結構子類型規則可以聲稱,如果類型 A的一個對象能處理類型 B的對象能處理的所有訊息(就是說,如果它們定義都同樣的方法),則 A是 B的子類型,不管二者任何一個是否從繼承自其他對象。不是對象類型的類型的健壯的結構子類型規則也是周知的。

帶有子類型的程式語言實現可分為兩大類:

•如果A<:B,類型A的任何值的表示也表示類型B的相同值,則為“包含實現”(inclusive implementation)。

•類型A的值可自動的轉換成類型B的值,則為“強制實現”( coercive implementation)。即類型強制轉換之意。

在面向對象語言中子類型所導致的子類型通常是包含的;聯繫整數和浮點數的子類型關係,它們有不同表示,通常是強制的。

在定義子類型關係的幾乎所有類型系統中,它是自反的(意味著對於任何類型 A有 A<: A)和傳遞的(意味著如果 A<: B並且 B<: C則 A<: C)。這得到了在類型上的預序。

記錄類型

記錄是命名的域(field)的集合。記錄類型(types of records)的子類型化包括寬度與深度兩種方式。

•寬度子類型化(width subtyping):給記錄增加更多的域。

•深度子類型化(depth subtyping):把超類型(supertype)的域替換為域的子類型。這僅能用於唯讀(immutable)記錄。

函式類型

對於函式類型T→ T,其子類型為S→ S,則T<: S且S<: T。參數類型S→ S為逆變,返回類型為協變。

允許副作用的語言,如大部分面向對象語言,子類型化還不足以保證安全在另一個上下文中使用。行為子類型化要求保持不變。

可變引用(mutable reference)的子類型化類似於函式參數與返回值的處理。只寫引用是逆變的;唯讀引用是協變的;可變引用是不變的。

類型強制

在強制子類型化系統(coercive subtyping system),子類型通過從子類型到超類型的隱式類型轉換函式得以定義。對於每個子類型關係 ( S<: T),一個強制關係 coerce: S→ T,使得任何對象 s為類型 S,可以視作對象 coerce( s)具有類型 T。類型強制函式可以複合:如果 S<: T且 T<: U,難么 s可以看作類型 u在複合強制關係( coerce∘ coerce)。類型到其自身的 coerce是同一函式 id。

相關詞條

相關搜尋

熱門詞條

聯絡我們