下邊要說的是我在語言學習過程中遇到一些不理解的問題,爲什麼要有virtual機制,還有什麼是晚捆綁。我當時學到這的時候可能困惑了一段時間,後來經過繼續學習測試等,得出了自己的結論,僅在這記錄一下。沒有太多的代碼實例,更像是我在囉嗦一些東西。
先說virtual
說道virtual肯定就想到多態,virtual是c++ 實現多態的一種方法,爲什麼要有這樣一套虛機制? 還是那些原則,代碼複用 ”想用不變的代碼去實現不同算法“,大概就是 懶吧。
舉個簡單的例子,(可能我現在在站的高度不夠,理解範圍有限,但這個例子至少是虛機制想要解決的問題中的一種)
有一個方法void test() 來測試不同國家的人說的語言,比如說有 Chinese Japanese French 等幾個類,類中都有一個speak() 方法
然後可以考慮這樣寫
void test(Chinese *p)
{
p->speak();
}
void test(Japanese*p)
{
p->speak();
}
void test(French *p)
{
p->speak();
}
這樣可以達到測試每個對象所說語種的目的。 但這樣看起來很不好,這幾個函數,只有參數類型不一樣,內部實現都一樣。那麼想 能不能把參數類型設置成某個特殊的類型,這個特殊的類型可以接收 Chinese Japanese French 等這些類的對象,然後在調用speak時,根據我實際傳進去的參數類型,再調用每個類中的speak方法。 如果可以的話就能只寫一個函數,實現不同的測試了
void test (special_class *p)
{
p->speak();
}
virtual機制就解決了上述問題,可以弄一個human的基類 然後讓Chinese Japanese French這幾個類繼承它, 然後語法上允許父類指針指向子類對象
void test(human * p)
{
p->speak();
}
然後問題是 test既然是能處理不同子類對象,那它如何確定該調用哪個子類中的speak()?
這就需要 晚捆綁啊,函數覆蓋啊 虛表啊什麼的那一套來實現,這個不是我困惑的重點,關於虛表可以看看這個
第二個 關於晚捆綁
學到這的時候我很是困惑,有早捆綁 或者叫 靜態綁定,比如說上邊的test 的參數 只是一個類類型 而不是指針或者引用的話,也就是說它沒有多態,只能處理一種類型的對象,
這時候調用speak 就是靜態綁定,在編譯階段就能完成。 如果有多態 那就叫晚捆綁(動態綁定) 綁定只能在運行時。困惑就在這了,
什麼叫運行時才能綁定啊????
在我的程序運行之前,我的所有代碼不是已經的寫定了麼,編譯之後 已經生成了 那些固定的彙編語句了啊,還有什麼是非得運行之後才確定麼????
說是不知道函數要處理的是哪個具體的子類對象,所以確定不了調用哪個函數, 那既然我調用test的代碼已經寫了
比如
Chinese a;
test(a);
那函數要處理的對象不就是Chinese 類型的麼 那就能確定調用的是Chinese 中的speak()了
編譯時就把p->speak(); 換成 call(Chinese中speak的地址) 不就行了麼,還有什麼是在運行之前不能確定的呢?????
?????????????????????????????????????????????????????????????????????????????
當時確實很困惑啊,後來想想 too young too naive 啊
按照上邊的想法,如果只調用test(a);
那是可以 把test函數中的speak調用改成call(Chinese中speak的地址),當程序執行到test(a);這句時 跳到改好的 test()函數的代碼部分 能往下執行,並調用了正確的函數。只要再稍微往後想一點, test()都被改成了 針對對象a的特定版本了, 那還能調用它 來處理其他子類對象麼? 不能處理了 ,那多態跑哪去了?
可見照上述我所想的這種靜態綁定是實現不了多態的。 那多態是如何實現的,是靠動態綁定實現的,在c++編程思想中講的比較明白了,爲了實現多態,編譯器在處理時會隱藏的插入一些內容
簡單說,就是因爲它不知道要處理的對象類型,不能直接去call某個函數的地址,它插入這段代碼,如果是有虛機制的對象,那在對象存儲空間裏能找到v_ptr 也就是虛表指針,這個不管哪個子類的對象只要有virtual 都會有這個指針,然後通過這個指針的偏移處理,在虛函數表中找到要調用的具體版本的函數的地址,再 call 就能實現不管處理什麼類型的子對象,都能找到v_ptr都能通過偏移 找到想要的函數,這就實現了 通用的處理。而這種處理方式,需要在程序運行是,找到傳進來的那個具體對象的存儲空間,然後在裏邊找到v_ptr 然後計算等等, 然後才能得到想要的函數, 也就可以理解 這是發生在運行時。
如果對這一塊有疑惑,推薦去看c++編程思想第二版 第十五章