#2 : 2005-4-19 08:58 AM
全部回覆
|
送花
(4)
送出中...
|
|
|
呼... 文章內分段引言真的很累, 我就不引了, 直接說比較快
其實我特別寫了個例子, 就是怕中文翻譯上造成困擾, 有沒有發現, 我沒有說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.
[如果你喜歡本文章,就按本文章之鮮花~送花給作者吧,你的支持就是別人的動力來源]
|