RSS   



  可打印版本 | 推薦給朋友 | 訂閱主題 | 收藏主題 | 純文字版  


 


 
主題: [轉貼] 什麼是多型的解釋   字型大小:||| 
Acute
論壇第一大毒王
等級: 18等級: 18等級: 18等級: 18等級: 18
論壇第一小神童

 . 積分: 3281
 . 精華: 8
 . 文章: 11574
 . 收花: 14037 支
 . 送花: 3260 支
 . 比例: 0.23
 . 在線: 323 小時
 . 瀏覽: 2250 頁
 . 註冊: 8008
 . 失蹤: 5360
#1 : 2005-4-17 07:58 PM     全部回覆 引言回覆


引用:
jocosn寫到:
同名異式(Polymorphism)=多型=動態繫結(Dynamic binding)

2. 多型在程式執行期利用動態連結(Dynamic Binding)的方式判斷訊息參數的類型
 與個數來決定運作的方法。
by 朱孝國


不知道是說哪個語言
但是以C++ 而言, 這一段不太對勁
C++ 的多形性靠的是編譯時期就決定好該呼叫哪個函式
C++ 的作法其實很簡單, 例如你寫個function 叫做Power ()
實際上, 他翻出來的函式名稱是Power!@#$%^ (), 後面那一串髒話, 就是參數的型態資訊
所以, 多形很容易就可以在編譯時期決定好, 該呼叫誰, 因為名字被偷改了

就正常的角度來看, 如果執行時期才去辨認參數... 決定呼叫哪個函式...
那程式的額外負擔有多重阿...
如果真有程式語言使用執行時期判斷多形性... 那寫出來的程式... 在4G 的CPU 上執行, 可能比隨便用個其他語言寫同樣效果的程式, 在100M 的CPU 執行還要慢
況且... 程式如何在執行時期才去辨認參數的型態跟個數, 恐怕都是一個無解的問題哩

Acute.



[如果你喜歡本文章,就按本文章之鮮花~送花給作者吧,你的支持就是別人的動力來源]
本文連接  
檢閱個人資料  發私人訊息  Blog  快速回覆 新增/修改 爬文標記
Acute
論壇第一大毒王
等級: 18等級: 18等級: 18等級: 18等級: 18
論壇第一小神童

 . 積分: 3281
 . 精華: 8
 . 文章: 11574
 . 收花: 14037 支
 . 送花: 3260 支
 . 比例: 0.23
 . 在線: 323 小時
 . 瀏覽: 2250 頁
 . 註冊: 8008
 . 失蹤: 5360
#2 : 2005-4-19 08:58 AM     全部回覆 引言回覆

呼... 文章內分段引言真的很累, 我就不引了, 直接說比較快

其實我特別寫了個例子, 就是怕中文翻譯上造成困擾, 有沒有發現, 我沒有說1, 3 兩點錯, 我只說針對第二點說明是錯的 ^^"
在class 內的function 因為繼承而產生的override, 其實是因為物件已經不同

我特別舉例, Power() function 具備不同參數時, 單提到function 行為, 而不提class 行為, 來顯示compiler 會怎麼去處理一個非class function 情形下, 多形如何真實達到.

其實class 也是利用類似觀念, 我們這樣想好了, 如果程式真的是所謂的, 執行時期去辨認物件, 那我們來思考一件最基本的動作, 一個compiler or 一個interpreter 如何去產生一段runtime 程式碼, 用來辨認物件? 那其實是幾乎永遠做不到的, 讓你自己寫一段程式碼, 然後可以任由user 定義一個物件, 然後你可以去辨識他, 你想一想, 你要寫的多複雜, 才能達到變認不出錯呢? 呵

在compiler 的實作方法上, 不同的class 具有不同的member, 即使繼承之後, 兩個相同名字的function, 其實已經分別隸屬於不同的兩個object, 因此, 他跟使用object 不同名字的function 意思是一樣的, 程式執行時期並沒有辨認上的困擾或需求, 他本來就已經決定好該怎麼去call, 因為物件已經不同. 只是從source level 去看時, 明明一樣的東西(名稱相同), 而他能準確的去call 不同的東西, 如此而已.

再用另一個簡單的角度去看, 如果, 如果, 如果, 程式是執行時期才去辨認該用哪個function, 那麼程式很輕易的就會掉入一個陷阱裏面, 假設function Power 有三種型態, 分別是: Power (int, int), Power (char, char), Power (int, char)
今天寫程式的人沒留意到, 寫了一個Power (char, int), 那麼, 這個錯誤是不是要等到執行時期才發現他錯? compiler 沒有能力也不該有能力發現他錯誤呢? 因為compiler 並不負責去辨認該怎麼call, right ? 可是實際上, 不管使用哪一種OO 語言, 他都是在compiler 時期就被挑出來的錯誤, 呵

當然, 某些特別的語言, 可能可以在compiler 之前就利用interpreter 先執行看看, 這時候, 就很難用我們習慣的說法去說, 他算不算執行時期才去辨認, 但是, 所謂執行時期才去辨認, 應該定義為: 程式有能力在執行時期辨認object, 而這個辨認行為不是藉由"監督程式, 或稱之為虛擬機器去達成的", 因為interpreter 可以"看見"整個程式的架構跟繼承關係, 他有能力辨認, 就跟compiler 有能力辨認一樣, 因為他是外部的解釋器, 他已經針對不同的東西, 建立一個lookup table, 所以, 他可以靠這份table 來索引相對關係上的物件, 而不是內部的"執行時期程式碼", 兩者其實不能等同論之.

再舉另一個限制來說明他是靠compiler 做到的. 在C++ 裏面, 我們可以用cast 的方法, 去改變基本型態, 例如, 你可以把int 透過cast 變成char or double, 但是, 他不允許你去cast 一個object or class, 為何不行呢? 如果compiler 編譯出來的程式具備"辨認物件"的能力, 那他幹嘛限制不允許cast 一個class? 只是辨認一下就搞定了不是嗎? 呵

不管哪一種語言, 他可以定義出不會混淆的語法機制及想要實現的語言願景即可, 但是, compiler 終究是一個程式, compiler要能被實作, so, 當真正實作時, 很多事情就會需要把他"確定"下來, 否則compiler就寫不出來了.

我不是很確定, 語言的定義者, 是不是真的用類似1F 那種說法 --- "多型在程式執行期利用動態連結(Dynamic Binding)的方式判斷訊息參數的類型與個數來決定運作的方法", 這種規定一定要怎麼做才可以的, 我個人認為, "語言定義者" 很少這麼幹, 因為把"實作"該怎麼做定義死, 會導致這個語言無法被開發出來才對, 因為只要實作上達不到語言要求, 就是一種錯誤, 況且, 這種說法, 意味著我前面說的, 如果call 一個function, 但是使用的參數沒有可以對應到的function, 這種現象, 應該等到執行時期才可以發現. 這種"強制解釋", 通常都是其他書籍作者"橫加"解釋上去的.以下舉個C 的例子來說這件事情.

C 語言裏面, 從來未曾規定, 參數傳遞上, 在堆疊內該怎麼做, 但是, 很多C 語言的書, 只要提到參數傳遞順序, 一定"斬釘截鐵"的說, C 語言的參數由後往前推入堆疊. 為什麼呢? 這部份是一個"實作"結果論, 因為, C 語言有個動態參數機制, 參數數目可以不是固定的, K&R 這項定義, 導致所有寫C compiler 的人, 只能由後往前將參數推入堆疊, 才能實作compiler, 不然compiler 做不出來. 當然, K&R 也從未說, 實際的參數, 由runtime辨認參數數目決定之, 因為這樣子, 大概又打死一堆寫compiler 的人. 當然, C 這種古老語言, 他定義的東西都比較單純而容易了解, 而且, 也不擔心把負擔加諸程式設計者身上, 從某個角度來看, 動態參數的確是可以解釋為: "執行時期辨認", 只不過, 這段辨認的code, 需要寫程式的人自己去負責, compiler 只是很簡單的提供幾個有關參數處理的function 給寫程式的人使用, 如此而已, 呵

沒頭沒尾敲了一大堆, 我想解釋的只是, 動態連結是無法在諸多條件不明的情形下完成的(也就是, 需要去辨認東西), jocosn提到Virtual Table, 其實這也是"實作" C++ 時產生的一種機制, Virtual Table並非完全runtime 才產生, compiler 已經先決定好這個table, 而載入時期, 已經把這個table 建立起來, 執行時期, 已經被決定怎樣使用這個table, 而不是執行時期才根據辨認結果來決定怎樣使用這個table, MS 也充分利用這個table 概念, 完成OLE 以及後來所有OLE 衍生出來的新規格 (個人對MS 的規格很少留意, so, OLE 之後啥米COM, DCOM... 一路的名詞沒去記 ^^").

呵, 這篇文該結尾了. 一些新的語言, 碰觸越來越少, 也很懶得再去看語言的定義, 都是遇到時, 看看sample 然後就隨手亂寫一通, 不寫Windows 程式有個快樂的地方, 就是不用看太多複雜而抽象的規格資料, 也不用被規定的死死的寫程式, CPU 任由自己高興的控制, 真是快樂阿, 哈

^^" 希望上述沒有寫錯的地方, 萬一有寫錯之處, 也歡迎繼續討論.

Acute.



[如果你喜歡本文章,就按本文章之鮮花~送花給作者吧,你的支持就是別人的動力來源]
本文連接  
檢閱個人資料  發私人訊息  Blog  快速回覆 新增/修改 爬文標記
Acute
論壇第一大毒王
等級: 18等級: 18等級: 18等級: 18等級: 18
論壇第一小神童

 . 積分: 3281
 . 精華: 8
 . 文章: 11574
 . 收花: 14037 支
 . 送花: 3260 支
 . 比例: 0.23
 . 在線: 323 小時
 . 瀏覽: 2250 頁
 . 註冊: 8008
 . 失蹤: 5360
#3 : 2005-4-19 11:37 AM     全部回覆 引言回覆


引用:
jocosn寫到:
加上原文
多型在程式執行期利用動態連結(Dynamic Binding)的方式.....

這裡所說的「動態連結(Dynamic Binding)」,不知道 Acute 是怎麼定義或去看?
我對底層沒有研究,有錯請加以指正。
舉一個例子,compile 時會先編譯多個 functions,執行時配合 object 型態去呼叫那一個 function,這就叫做動態連結,所以只要在記憶體還是哪裡配置一個區塊,專放物件要存放的資料就好。
所以沒有產生額外的程式碼,只有產生額外的資料。

至於 Power (char, int) 這個錯誤如果等到執行時期才發現,我覺得應該會因為沒有定義到這個 function,所以當然編譯錯誤,不用等到執行,這好像跟多型沒關係?就像你呼叫一個你沒定義的變數 X 一樣。


我的意思就是, 原文的描述是一種錯誤阿 @_@
我們來看動態連結應該是啥
首先, DLL 稱之為, 動態連結程式庫. 他為何叫做動態連結程式庫? 因為compiler/linker 不知道應該跟誰連結, 只知道, 程式被指定, 要去呼叫一個外部的東西, 這個東西, 至少要等到執行時期的載入階段, 才能確認.  這種動態連結, 其實也是已經知道一切, 只是最終的程式碼在載入時期才去找到, 並且連結, so, 他並不是執行時期才根據啥去判斷, 他做不到, 他是載入時期. 根據指定的程式庫去找到程式碼, 並且完成連結, 之後執行.

動態連結程式庫允許執行時期進行連結, 但是, 不好意思, compiler/linker 沒能力做, 必須程式撰寫者, 自己去進行載入, 並且進行連結, 以C/C++ 來看, 就是載入後, 利用函式指標去指到正確的function. 為什麼要程式設計師自己做? 因為動態連結沒辦法去辨認, 那太困難了, 寫程式的人知道自己在幹嘛, so, 讓寫程式的人自己動手, 簡單又乾脆. 如果要compiler/linker 幫忙, 一律只能在載入時期就必須決定!

再來看OO 語言的多形性的例子, 先來看純function 的部份, 他沒有任何辨識或判斷, 也沒有需要等到執行時期才知道, 在compiler 時期, 就已經決定好一切, 該call 哪個function, so, 他沒有任何所謂執行時期的動態連結行為發生. 而C++ compiler 也用一個最簡單的作法, 把參數條件加入實際function name裏面, 所以, linker 變得很簡單. 把這個稱之為"執行時期利用動態連結..." 我覺得是不對的. 因為他本來就是預先決定好的, 而不是臨時才決定, compiler 早就賦予每個不同參數的function 有不同的"名字", 只是撰寫程式者, 看到的是同一個"名字" 而已.

再來看複雜一點的class or object 行為, class A 有個function A, class A2 繼承class A, 然後一樣有個function A, 從人去看, 沒錯, 都是叫做A, 可是, 從compiler 去看, 他知道class A 跟A2 是不同的東西, 在compiler 時期, 他就已經可以知道, 當你要呼叫function A 時, 是呼叫class A or class A1 的function A. so, 他跟純function 意思還是一樣的, 在compiler 時期, 所有一切都已經決定好, 他還是不能稱之為執行時期利用動態連結...

如果OO 語言真的具備動態連結能力, 應該是要能正確執行以下程式: (這是無法compiler 的程式)

void Power (int i, j);
void Power (char a, char b);
void Power (int, char);

functionDiffcult (void *p1, void *p2, void *p3, void *p4)
{
      Power (*p1, *p2);
      Power (*p3, *p4);
      Power (*p3, *p1);
}

functionEasy ()
{
     char a, b;
     int i, j;
     void *p1, *p2;

     p1 = &a;
     p2 = &b;
     Power (*p1, *p2);

     p1 = &i;
     Power (*p1, *p2);

     p2 = &j;
     Power (*p1, *p2);

     FunctionDiffcult (&a, &b, &i, &j);
     FunctionDiffcult (&i, &j, &a, &b);
}

上面的程式, 只是一個示意碼, 或者稱之為虛擬碼, 他不能compiler 也不能執行, 我要解釋的只是, 哪個語言有能力去根據一個不知道型態的內容, 然後執行時期去辨認他是啥型態, 然後決定該怎樣call !

事實上, OO 語言都是compiler 已經根據資料型態, 預先決定好該實際去call 哪個function, 而不是"執行時期根據參數型態動態連結", 如果是, 那應該要有一個語言有能力compiler & 執行上面那一段虛擬碼. 程式能夠去"辨認" 參數是啥, 然後決定呼叫三個function 當中的哪一個. 但是, 這是不可能可以做到的

Acute.



[如果你喜歡本文章,就按本文章之鮮花~送花給作者吧,你的支持就是別人的動力來源]
本文連接  
檢閱個人資料  發私人訊息  Blog  快速回覆 新增/修改 爬文標記
Acute
論壇第一大毒王
等級: 18等級: 18等級: 18等級: 18等級: 18
論壇第一小神童

 . 積分: 3281
 . 精華: 8
 . 文章: 11574
 . 收花: 14037 支
 . 送花: 3260 支
 . 比例: 0.23
 . 在線: 323 小時
 . 瀏覽: 2250 頁
 . 註冊: 8008
 . 失蹤: 5360
#4 : 2005-4-20 01:23 AM     全部回覆 引言回覆


引用:
jocosn寫到:
那應該怎麼改才對?


2. 多型在程式編譯時期利用判斷訊息參數的類型與個數來決定運作的方法。

應該這樣子, 比較合理 ^^"

Acute.



[如果你喜歡本文章,就按本文章之鮮花~送花給作者吧,你的支持就是別人的動力來源]
本文連接  
檢閱個人資料  發私人訊息  Blog  快速回覆 新增/修改 爬文標記
Acute
論壇第一大毒王
等級: 18等級: 18等級: 18等級: 18等級: 18
論壇第一小神童

 . 積分: 3281
 . 精華: 8
 . 文章: 11574
 . 收花: 14037 支
 . 送花: 3260 支
 . 比例: 0.23
 . 在線: 323 小時
 . 瀏覽: 2250 頁
 . 註冊: 8008
 . 失蹤: 5360
#5 : 2005-4-20 05:08 PM     全部回覆 引言回覆


引用:
jocosn寫到:
我的程式碼是因為看不小神童在問什麼,所以用到 OVERLOADING,完全是個錯誤的範例,造成誤解請見諒。


呵, 我都沒問啥阿, 我只是說, 那個描述是有問題的, 如此而已哩

Acute.



[如果你喜歡本文章,就按本文章之鮮花~送花給作者吧,你的支持就是別人的動力來源]
本文連接  
檢閱個人資料  發私人訊息  Blog  快速回覆 新增/修改 爬文標記
Acute
論壇第一大毒王
等級: 18等級: 18等級: 18等級: 18等級: 18
論壇第一小神童

 . 積分: 3281
 . 精華: 8
 . 文章: 11574
 . 收花: 14037 支
 . 送花: 3260 支
 . 比例: 0.23
 . 在線: 323 小時
 . 瀏覽: 2250 頁
 . 註冊: 8008
 . 失蹤: 5360
#6 : 2005-4-20 11:13 PM     全部回覆 引言回覆


引用:
Acute寫到:

引用:
jocosn寫到:
那應該怎麼改才對?


2. 多型在程式編譯時期利用判斷訊息參數的類型與個數來決定運作的方法。

應該這樣子, 比較合理 ^^"

Acute.


忘了說, 上面的說法, 是為了彰顯原文這方面的描述不太對勁, 所以, 才會寫上 "XX時期"

就語言定義而言, 基本上, 很少會去描述一個動作應該怎樣做, 也就是, 語言定義裏面, 頂多是寫成 (甚至於很可能不寫, 因為沒必要規定作法):
多型利用判斷訊息參數的類型與個數來決定運作的方法。

實際上如何實作, 則由製作compiler 的人去根據合適的方法達到目標

補述:
通常會出現"結果論" 或"推測論", 都是由其他介紹相關語言之書籍的作者寫進去的.
所謂結果論, 是指, 根據某個或大多數compiler 作法, 而把該作法加入語言介紹中, 變成一個雖然沒錯, 但是不適當的描述.
所謂"推測論", 也是其他人寫語言介紹書時寫進去的, 但是, 因為該作者可能根本不懂compiler 該怎麼做, 只好胡思亂想隨便猜. 個人推測(我也在亂猜), 原文的第二點, 就是作者的"推測"結果, 只是, 該推測結果, 是無法做到的, 呵

一般而言, 真要了解一個語言, 要直接看語言定義的書籍, 這種書, 通常只有一本(俗稱:Bible), 而且, 是由語言定義者直接撰寫出來的. 以C 而言, 就是K&R 親手撰寫的The C programming language. 以C++ 而言, 就是The C++ programming language. (作者我忘了是誰) 用這種書籍當學習語言的入門會很辛苦, 因為書籍的目的是詳盡的介紹語言, 而不是教導如何學習該語言, 但是, 當你真想學好一個語言, 你就是必須花過一次時間, 把bible 仔細研讀一次, 這樣子, 你才能真正了解該語言, 並且不會被曾經看過的書誤導.

Acute.



[如果你喜歡本文章,就按本文章之鮮花~送花給作者吧,你的支持就是別人的動力來源]
本文連接  
檢閱個人資料  發私人訊息  Blog  快速回覆 新增/修改 爬文標記

   

快速回覆
表情符號

更多 Smilies

字型大小 : |||      [完成後可按 Ctrl+Enter 發佈]        

溫馨提示:本區開放遊客瀏覽。
選項:
關閉 URL 識別    關閉 表情符號    關閉 Discuz! 代碼    使用個人簽名    接收新回覆信件通知
發表時自動複製內容   [立即複製] (IE only)


 



所在時區為 GMT+8, 現在時間是 2024-4-28 07:46 AM
清除 Cookies - 連絡我們 - TWed2k © 2001-2046 - 純文字版 - 說明
Discuz! 0.1 | Processed in 0.028613 second(s), 7 queries , Qzip disabled