2010-02-09 71 views
17

如果沒有函數重載,則函數名稱作爲函數代碼的地址,並且在函數被調用時,其地址很容易使用其名稱查找。但是,如果函數重載,程序如何找到正確的函數地址?是否有類似於虛擬表的隱藏表,用於存儲帶有地址的重載函數?非常感謝!在C++中,函數重載通常如何實現?

+4

我認爲,那些建議名字混搭的人會被誤導。它不像編譯器破壞名稱,只是在重名的名稱中進行查找。它需要從可用方法中推斷出適當的類型。一旦這樣做,它就知道要調用哪種方法。然後它將使用重名的名稱作爲_last_步驟。名稱修改不是決定調用哪個重載函數的先決條件。 – 2010-02-09 08:34:47

+0

也許這個評論應該出現在你指的一個誤導性答案中? – Manuel 2010-02-09 08:37:24

+0

太多了,所以我把它留在這裏。 – 2010-02-09 08:39:17

回答

11

編譯器可以查看調用,並將其與已知的現有重載實現進行匹配,然後選擇正確的調用。不需要動態表格,它在編譯時靜態完全可行。

更新:刪除了我試圖通過顯示編譯器可以選擇的不同名稱的函數來說明這個概念。

+0

人們說這個techniq名字是Mangling。搜索此關鍵字。 – SunnyShah 2010-02-09 08:05:33

+4

名稱修改只是爲了區分標識符的名稱,是否過載。名稱修改的主要目的不是爲了迎合超載,而是爲了避免命名衝突。在重載的情況下,編譯器必須確定要調用哪個方法,並且這是主邏輯所在的位置。我相信OP想知道這是編譯時間還是運行時間。 – 2010-02-09 08:24:42

+0

這並不準確,它通常是需要計算呼叫地址的鏈接器。名字裝飾非常重要。是的,如果函數碰巧位於同一翻譯單元中,則有機會省略鏈接請求。實際發生的是一個實現細節。 – 2010-02-09 09:25:31

0

它,我相信,通過名稱重整實現:

你知道作爲foo的實際名字類似int_foo功能(INT)和Foo(雙)()和double_foo()(或類似的,我我不完全確定C++使用的特定語義)。這意味着C++符號通常比它們在代碼中給出的名稱大一個數量級。

3

重載函數在編譯時解析。編譯器爲給定的一組參數找到合適的匹配,並簡單地通過其地址調用相應的函數(void foo(int)void foo()實際上是兩個完全獨立的函數 - 如果代碼中有foo(4),編譯器知道要調用哪個函數)。

5

如果你是在談論同一個類的重載方法,就像這樣:

void function(int n); 
void function(char *s); 
... 

objectInstance->function("Hello World") 

這是一個編譯時啄。編譯器知道(或在某些情況下,最好猜測)此時調用哪個方法。

我在這個問題中做了一個評論,我在這裏重複一遍。

我認爲那些暗示名字混搭的人是錯誤的。它不像編譯器破壞名稱,只是在重名的名稱中進行查找。它需要從可用方法中推斷出適當的類型。一旦這樣做,它就知道要調用哪種方法。然後它使用錯位的名稱作爲最後的步驟。名稱修改不是決定調用哪個重載函數的先決條件。

+0

給出-1的人。至少發表評論。如果信息不準確,我可以刪除/編輯帖子。給我一個學習的機會! – 2010-02-09 07:59:15

+0

我想那個人(不是我)低估了,因爲你沒有給出明確的答案。相反,你只是說「編譯時間」和「編譯器只知道該怎麼做」,這確實有點不準確。 – AndiDog 2010-02-09 08:34:25

+0

嗯,名稱不準確,IMO。我們可以說最好的是「編譯器知道」。每個編譯器都可能有自己的實現。 – 2010-02-09 08:36:53

-1

函數簽名是由函數名+參數(一個或多個)類型(一個或多個)

12

Name mangling的。

這一切都在編譯時完成。 C++編譯器實際修改你給它內部的功能名稱,因此像

int foo(int a, float b, char c) 

函數內部得到相當於

func_foo_int_float_char() 

的名稱(真正的符號通常是這樣[email protected]@@[email protected]一些官樣文章)。

正如您所看到的,名稱是根據傳遞的參數的確切數量和類型進行修飾的。所以,當你調用一個函數時,編譯器很容易查看你正在傳遞的參數,用它們裝飾函數名稱,並拿出正確的符號。例如,

int a, b; float f; char c; 
foo(a,f,c) ; // compiler looks for an internal symbol called func_foo_int_float_char 
foo(a,b,c) ; // compiler looks for a symbol called func_foo_int_int_char 

再次,它們都是在編譯時完成的。

+6

這是相反的。編譯器首先查看所有foos,根據標準中的所有規則選擇匹配的一個,然後可能爲鏈接器發出一個錯位的名稱。 – UncleBens 2010-02-09 14:22:06

+0

非常豐富,謝謝。 – Dasaru 2012-06-25 14:39:27

-1

即使沒有函數重載,編譯器通常會調用mangle函數和變量名。它被稱爲name mangling。它發生在C和C++中。函數名稱可以通過以下方式進行修飾:(1)調用約定,(2)C++函數重載,(3)類成員函數。

GNU binutil c++filt可以去除裝飾此重整名稱,並在Windows中,有UnDecorateSymbolName

-1

C++編譯器使用名稱重整(不同的名稱爲每個過載)在對象文件中的功能之間進行區分。例如

int test(int a){} 
int test(float a,float b){} 
int test(double a){} 
int testbam(double a){} 

會產生符號名__Z4testi__Z4testff__Z4testd__Z7testbamd。這個名字是非常依賴編譯器的(可悲的),也是爲什麼C經常比C++更受歡迎的原因之一。

當調用函數test時,編譯器將針對每個函數重載的給定參數類型和參數數量進行匹配。函數原型然後用於找出應該調用哪一個。