定義 由於子類型關係的存在,某個對象可能同時屬於多種類型,因此,子類型是一種類型多態的形式,也被稱作子類型多態(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的子類型而相互之間無子類型關係。
編程者可利用子類型來以比沒有它更抽象的方式來寫代碼。考慮下面的例子:
function max (x as number, y as number) is if x < y then return y else return x end 如果整數和實數都是number的子類型,則二者任何類型都可以傳遞給這個函式。為此,子類型經常被認為是一種形式的
多態性 。上述例子也可以比較於 C++ 語言的
模板 。
在
類型論 中,子類型關係經常寫為<:,有著
A <:
B 意味著
A 是
B 的子類型。在類型論中子類型可用如下事實來特徵化,如果
A <:
B ,類型
A 的任何表達式也可被給予類型
B ;立法這個特徵化的形式類型規則叫做“包容”規則。
方案 類型理論研究者區分兩類類型系統:
上面描述的基於類的面向對象子類型描述是名義的;面向對象的結構子類型規則可以聲稱,如果類型
A 的一個對象能處理類型
B 的對象能處理的所有訊息(就是說,如果它們定義都同樣的
方法 ),則
A 是
B 的子類型,不管二者任何一個是否從繼承自其他對象。不是對象類型的類型的健壯的結構子類型規則也是周知的。
帶有子類型的程式語言實現可分為兩大類:
在面向對象語言中子類型所導致的子類型通常是包含的;聯繫整數和浮點數的子類型關係,它們有不同表示,通常是強制的。
在定義子類型關係的幾乎所有類型系統中,它是自反的(意味著對於任何類型A 有A <:A )和傳遞的(意味著如果A <:B 並且B <:C 則A <:C )。這得到了在類型上的預序。
記錄類型 記錄是命名的域(field)的集合。記錄類型(types of records)的子類型化包括寬度與深度兩種方式。
函式類型 對於函式類型T
1 → T
2 ,其子類型為S
1 → S
2 ,則T
1 <: S
1 且S
2 <: T
2 。參數類型S
1 → S
2 為
逆變 ,返回類型為
協變 。
允許副作用的語言,如大部分面向對象語言,子類型化還不足以保證安全在另一個上下文中使用。行為子類型化要求保持
不變 。
可變引用(mutable reference)的子類型化類似於函式參數與返回值的處理。只寫引用是逆變的;唯讀引用是協變的;可變引用是不變的。
類型強制 在強制子類型化系統(coercive subtyping system),子類型通過從子類型到超類型的隱式
類型轉換 函式得以定義。對於每個子類型關係 (
S <:
T ),一個強制關係
coerce :
S →
T ,使得任何對象
s 為類型
S ,可以視作對象
coerce S → T (
s )具有類型
T 。類型強制函式可以複合:如果
S <:
T 且
T <:
U ,難么
s 可以看作類型
u 在複合強制關係(
coerce T → U ∘
coerce S → T )。類型到其自身的
coerce T → T 是同一函式
id T 。