2016-08-13 79 views
-1

使用關鍵字virtual時,如果compliler-linker知道調用者和被調用者的位置(地址/偏移量保存在表中等),那麼所有地址都可以在exe中被硬編碼。那麼它不應該被稱爲早期綁定。如果僅在執行調用者代碼(操作系統中的地址?)時獲得地址,則這必須是真正的後期綁定。如果後期綁定是首選,爲什麼編譯器 - 鏈接器不想使用它(不管源代碼是否使用了虛擬關鍵字)?薩姆早期和晚期綁定是如何實現的?

+3

目前尚不清楚你在說什麼。你似乎在混淆C++多態和庫鏈接。這些是不同的事情。 –

+2

'如果compliler-linker知道調用者和被調用者的位置(地址/偏移保存在表中等),那麼所有地址都可以在exe中被硬編碼 - 如果可以的話。一般情況下它不能。然後它只是一個函數ptr(在表中)。 – lorro

回答

2

考慮這個例子:

#include <iostream> 
#include <memory> 

class Base { 
public: 
    virtual void foo() = 0; 
}; 

class Derived1: public Base { 
public: 
    virtual void foo() { std::cout << "impl1" << std::endl; } 
}; 

class Derived2: public Base { 
public: 
    virtual void foo() { std::cout << "impl2" << std::endl; } 
}; 

int main() { 
    int c; 
    std::cin >> c; 
    std::unique_ptr<Base> inst; 
    if (c) inst.reset(new Derived1()); 
    else inst.reset(new Derived2()); 
    inst->foo(); 
} 

在這裏,你不知道哪個FOO()實現調用,直到你真正運行的程序。所以是的,C++有真正的晚期綁定。

後期綁定的不利之處在於,當調用虛擬方法時存在一個很小的開銷。由於C++可以用在一些超級優化的計算庫中,所以決定是否使用它是留給程序員的。

正如Matteo Italia在評論中指出的那樣,虛擬方法可以防止內聯。這可能會對性能產生顯着影響(與通話開銷不同,後者幾乎從不會被注意到)。

+0

關於虛擬通話費用:與常規通話相比,虛擬通話本身通常並不昂貴(只要對分支預測器而言「容易」),通常很大的成本就是錯失了內聯機會。我不得不在內部循環中刪除虛擬呼叫,在某些情況下可以獲得2倍或更多的加速。 –

2

如果在呼叫者代碼被執行僅獲得地址(從操作系統地址?)

它不來自於操作系統,但是從(有效)的函數的指針。

那麼這必須是真正的晚期綁定。

它是。

如果後期綁定是首選,爲什麼編譯器,鏈接器並不一定要使用它(不考慮如果源代碼中使用的虛擬關鍵字,或者不是)?

那麼,這不是首選。速度非常慢。這不一定是因爲「物理」函數調用花費的時間比正常的要長很多;由於額外的間接方法需要更長的時間,但真正的不利之處在於你的調用無法完全消除(通過內聯),因爲編譯器不知道哪個函數最終會在運行時被調用。

除非您需要它,否則您不想使用它,即您需要虛擬呼叫。

這個決定與您在「我應該只是調用一個函數還是應該從一堆選項中查找映射中的函數指針並調用我想要的函數指針那?」您使用正確的工具來完成這項工作,但額外的靈活性會帶來成本。

+0

@DavidHaim:是的,這使得它在我的書中「非常慢」:)對內聯等等說再見。當然,實際上量化是一件複雜的事情。 –

+0

我會澄清它。 –

相關問題