簡介
特定多態的名字來源於其發明人克里斯托弗·斯特雷奇於1967年8月在哥本哈根的電腦程式設計暑期學校發表了著名論文Fundamental Concepts in Programming Languages中首次提出了參數多態、特設多態、左值、右值等概念。。特設多態與參數多態相對。 ad hoc在這裡並不是貶義,而是指這類多態並不是類型系統的基本特性,不是像參數多態那樣適用於無窮多的類型,而是針對特定問題的解決方案。
換言之,參數多態對各模板參數的實現,是根據模板的通用(generically)的行為的抽象,即泛型的語義;而特設多態可以針對不同的版本實現完全不同的行為,或曰對於每個不同的模版參數都有單獨的版本來應對。打個比方:假如我們要把原材料切成兩半——
•參數多態:只要能“切”,就用工具來切割它;
•特設多態:根據原材料是鐵還是木頭還是什麼來選擇不同的工具來切。
C++ 模板
C++ 的模板是特設多態的著名例子。對於 C++ 模板而言,僅有當一個模板被填上類型(或非類型)參數時才會接受編譯器的檢查及編譯,而不是預先進行檢查(指對模板內容檢查)以確定何種參數可以交給這個模板。另外,C++ 模板的全特化、偏特化,其本質上也是對該模板所代表的“較一般情況”做出的“特例”。特別而言,模板全特化是針對特定情況直接給出專門的實現、也即可以與普通的模板具有完全不同的內容,本質上與函式重載沒有區別,匹配特設多態的概念。
早綁定
多態的早綁定(early binding)是在編譯期,編譯器完成多態的分派機制:把多態函式、多態類型的名字根據模板參數綁定到具體的模板實現。
特別的多態性是一個調度機制:控制移動通過一個名為函式是派往其他各種功能,而不必指定具體的函式被調用。重載允許多個函式取不同類型具有相同名稱的定義;的編譯器或翻譯自動確保調用正確的函式。這種方式,附加功能列表的整數,字元串列表,列表的實數,可以編寫等等,所有被稱為附加並正確的附加功能將被稱為基於列表的類型被附加。這不同於參數多態性,需要寫的一般函式,使用任何類型的列表。使用重載,可以有一個函式執行兩個完全不同的東西傳遞給它的基於類型的輸入;這是不可能的,參數多態性。看的另一種方法重載是一次例行的惟一確定的而不是由它的名字,但組合的名稱和數量,訂單和類型的參數。
這種類型的多態是很常見的面向對象程式語言,很多的允許運營商是超載的方式類似於函式(見操作符重載)。有些語言不動態類型和缺乏特別的多態性(包括類型類)有較長的函式名等print_int,print_string等等。這可以被視為優勢(更具描述性的)或一個缺點(過於冗長)取決於一個人的觀點。
有時從重載中獲得一個優勢是專業化的外觀,例如,一個函式具有相同名稱的可以以多種不同的方式實現,每個最佳化為特定數據類型的運作方式。這可以提供一個方便的界面代碼,需要專門的多個情況下由於性能的原因。類型系統的缺點是不能保證不同實現的一致性。
由於重載是在編譯時完成的,它不是一個代替後期綁定發現在子類型多態性.
晚綁定
多態的晚綁定(late binding)是在運行期,程式確定即將要調用的多態函式的實現。Smalltalk實現了這種晚綁定機制。
在Smalltalk,重載是在運行時完成的方法(”功能實現”)為每一個重載的訊息(“重載函式”)解決當他們即將被執行。這種情況發生在運行時,編譯後的程式。因此,多態是由子類型多態性和其他語言一樣,也是在功能擴展特設在運行時多態。
更仔細的觀察也表明,Smalltalk提供一個稍微不同的各種特別的多態性。Smalltalk以來晚綁定執行模型,因為它提供了對象處理信息的能力,不理解,可以繼續使用多態性實現功能沒有明確重載一個特定的信息。這可能不是一般推薦的日常編程實踐,但它可以是非常有用的在實現代理。
也,而在一般條款常見的類方法和構造函式重載不考慮多態性,有更多的類是普通對象的統一語言。在Smalltalk,例如,類是普通對象。反過來,這意味著訊息類可以重載,也可以創建對象,像類沒有他們的類繼承的類的層次結構。這些都是有效的技術可以用來利用Smalltalk的強大的反射功能。類似的安排等也可能在語言自我和官腔。
例子
加法運算符+假設可以運用到如下的情形:
1 + 2 = 3
3.14 + 0.0015 = 3.1415
1 + 3.7 = 4.7
[1, 2, 3] + [4, 5, 6] = [1, 2, 3, 4, 5, 6]
[true, false] + [false, true] = [true, false, false, true]
"bab" + "oon" = "baboon"
1.1 + 2 = 3
2.3.14 + 0.0015 = 3.1415
3.1 + 3.7 = 4.7
4.[1, 2, 3] + [4, 5, 6] = [1, 2, 3, 4, 5, 6]
5.[true, false] + [false, true] = [true, false, false, true]
6."bab" + "oon" = "baboon"
為此,需要的重載實現:
•第一種情形,需要整型加法;
•第二、第三種情形,需要浮點型加法。其中第三種情形需要隱式類型轉換(type coercion)。
•第四、第五種情形,需要list的連線操作;
•第六種情形,需要字元串字面量的連線操作。
因此,運算符名字+實際上使用了三到四種完全不同的函式實現。