我試圖查看虛擬函數是在編譯期間還是在運行時確定的。 雖然看我發現了一些動態鏈接/後期綁定 但我不明白,如果它意味着函數本身確定在可執行文件之前或可執行文件中編譯期間。虛擬函數是在編譯過程中確定的嗎?
有人能解釋一下嗎?
我試圖查看虛擬函數是在編譯期間還是在運行時確定的。 雖然看我發現了一些動態鏈接/後期綁定 但我不明白,如果它意味着函數本身確定在可執行文件之前或可執行文件中編譯期間。虛擬函數是在編譯過程中確定的嗎?
有人能解釋一下嗎?
對於虛擬函數解析是在運行時完成的。當你有一個對象的實例時,只有在程序運行時才知道調用哪個方法的決議,因爲只有在運行時你才知道這個實例的確切類型。對於非虛函數,這個解決方案可以在編譯時完成,因爲已知只有這個方法可以被調用,並且不能有子類覆蓋它。這也是爲什麼虛擬方法調用速度稍慢(絕對可以忽略但比非虛擬方法調用慢)的原因。 This article更詳細地解釋了這個概念。
虛擬函數調用的名稱查找,重載解析和訪問檢查發生在編譯時用於調用虛函數調用的對象表達式的'static'類型中(即,如果對象表達式是類型指針或對多態基類的引用)。
但是,在運行時調用的實際函數取決於基類指針或引用指向的對象表達式的動態類型。
通常在運行時解析虛函數。原因很明顯:您通常不知道在呼叫站點將會調用什麼實際對象。
Base *x; Derived *y;
Call1(y);
void Call1(Base *ptr)
{
ptr->virtual_member();
// will it be Base::virtual_member or Derived::virtual_member ?
//runtime resolution needed
}
這樣的情況,當現在還不清楚什麼功能將在某個地方的代碼調用,只有在運行時,它實際上是確定的,被稱爲末結合。
但是,在某些情況下,您可能知道函數。例如,如果你不用指針調用:
Base x; Derived y;
Call2(y);
void Call2(Base ptr)
{
ptr.virtual_member();
// It will always be Base::virtual_member even if Derived is passed!
//No dynamic binding necessary
}
但是如果我有例如類Animle,它有一個虛擬打印()裏面的內容。和另一個覆蓋print()的Cat類。如果我嘗試創建:Animle a = new Cat();打印();貓c =新貓(); c.print();所以第一個將在運行時確定,那麼第二個呢? – 2010-09-05 16:16:35
那麼在這種情況下,調用哪個方法的解決方法是在運行時執行的,因爲可能有'DomesticCat'派生自'Cat'並覆蓋'print'方法本身。 – 2010-09-05 16:17:32
在Cat上調用重寫的方法 - 這意味着被覆蓋。 – cyborg 2010-09-05 16:19:08