C++相對於C語言而言支持函數重載是其極大的一個特點,相信在使用C語言的時候大家如果要寫一個實現兩個整型數據相加的函數還要寫一個浮點型數據相加的函數,那麼這兩個函數的名字絕對不可以一樣,這樣無疑在我們使用這個函數的時候增加了複雜性,但是在C++中我們卻可以很好的解決這個問題,因為在C++中函數是支持 ...
C++相對於C語言而言支持函數重載是其極大的一個特點,相信在使用C語言的時候大家如果要寫一個實現兩個整型數據相加的函數還要寫一個浮點型數據相加的函數,那麼這兩個函數的名字絕對不可以一樣,這樣無疑在我們使用這個函數的時候增加了複雜性,但是在C++中我們卻可以很好的解決這個問題,因為在C++中函數是支持重載的也就是說兩個函數的函數名可以一樣,這樣並不會出現函數名重定義的問題,但是我們在使用的時候也要遵守一些規定,這些規定我們會在接下來的討論中提到,下麵我們就來分析在C++中函數是如何實現函數的重載的。
在這裡我們用C語言和C++分別寫兩個函數,通過函數的符號表來觀察函數名在經過編譯之後究竟是什麼形式的
下麵就是我們的測試代碼:
1 #include<iostream> 2 3 using namespace std; 4 5 6 7 int Add(int x, int y) 8 9 { 10 11 int z = 0; 12 13 z = x + y; 14 15 return z; 16 17 } 18 19 20 21 double Add(double x, double y) 22 23 { 24 25 double z = 0; 26 27 z = x + y; 28 29 return z; 30 31 } 32 33 34 35 int main() 36 37 { 38 39 cout<<Add(1,3)<<endl; 40 41 cout<<Add(1.5,3.5)<<endl; 42 43 return 0; 44 45 }
在VS2008的編譯環境下:
我們生成.map文件,然後可以查看函數在經過編譯之後的函數名稱為下圖所示:
不難發現上圖中函數命名的一些規律(當然這個規律只是片面的針對於VS2008編譯環境):
1.以“?”開始和以”@Z”結尾
2.函數的名稱緊接“?”之後
3.在函數明德後面分別是函數返回值類型修飾符、參數列表中的參數的類型修飾符
下麵我們把這個相同的函數改為c語言的代碼
代碼如下:
1 //#include<iostream> 2 3 //using namespace std; 4 5 #include<stdio.h> 6 7 8 9 10 11 int Add(int x, int y) 12 13 { 14 15 int z = 0; 16 17 z = x + y; 18 19 return z; 20 21 } 22 23 24 25 double Add(double x, double y) 26 27 { 28 29 double z = 0; 30 31 z = x + y; 32 33 return z; 34 35 } 36 37 38 39 int main() 40 41 { 42 43 //cout<<Add(1,3)<<endl; 44 45 //cout<<Add(1.5,3.5)<<endl; 46 47 return 0; 48 49 }
這時我們編譯的話就會出現錯誤:
這裡告訴我們函數名出現重定義
那麼這是為什麼呢?
這時我們註釋掉一個函數然後編譯後查看.map文件,查看函數重命名之後的名稱
這裡我們可以發現函數在編譯之後重命名的名稱僅僅只是在函數名稱的前面加上了一個"_"(下劃線),這樣我們就不難分析了,C和C++編譯的時候對函數的重命名機制是完全不一樣的
1.C語言中僅僅只是在函數的名稱的前面加上了"_"(下劃線)
2.C++有自己的命名修飾規則,他會根據函數的參數列表中變數的類型等進行相應的類型修飾
雖然C++支持函數的重載但是我們在使用的時候也要註意以下幾點:
1.函數的重載只是出現在同一作用域,例如假如兩個工程里的函數名稱相同,但是他們也不是函數的重載
2.函數名相同,函數的參數列表不同,返回值可同可不同,為什麼函數返回值可同可不同呢?
這是因為在不同的編譯環境下對於函數名稱的修飾並不是相同的,下麵就是在Linux環境下函數編譯後重命名的形式:
仔細觀察不難發現在Linux環境下的函數重命名的一些規則:
1.以“_Z”z作為開頭,緊隨其後的數字是函數名稱的單詞的個數
2.函數的名稱後面有函數的參數列表中參數的類型修飾符,i是int型,d是double型
通過以上的闡述相信大家可以對C++中為什麼可以實現函數重載有了清晰的認識,那麼我們也就不難回答為什麼在C++中調用被C編譯過後的函數應該在前面加上 extern "C" 聲明瞭。
這是因為我們當前是處於c++語言環境,這個時候我們如果不指定要調用的那個函數是用C語言編譯的函數,那麼當前在C++文件中編譯時就會報錯說是該函數是一個無法解析的外部符號,因為在編譯運行的時候我們當前的程式會從符號表中去找相應的函數名,可是C++和C編譯後生成的符號表中函數的名是不同的,那麼這個函數也就是一個無法解析的外部符號了,但是當你用extern “C” 指明該函數是用C語言編譯的函數,那麼當前代碼在編譯運行的時候就會從用C語言編譯的那個符號表文件中去查找相應的函數名,這樣整個程式的編譯運行費也就沒有問題了。