C++入門語法之函數重載詳解
寫在前面
關於C語言的編譯與鏈接不懂的可以看一下下面的文章,先回顧一下以前的知識。
詳解C語言的編譯與鏈接
1 函數重載的概念
函數重載:是函數的一種特殊情況,C++允許在同一作用域中聲明幾個功能類似的同名函數,這些同名函數的形參列表(參數個數 或 類型 或 順序)必須不同,常用來處理實現功能類似數據類型不同的問題。
//1.函數的參數個數不同 #include <iostream> using namespace std; void print() { cout << "print()" << endl; } void print(int a) { cout << "print(int a)" << endl; } int main() { print(); print(1); return 0; }
執行結果如下:
print()
print(int a)
請按任意鍵繼續. . .
//2.函數的參數類型不同 #include <iostream> using namespace std; void print(double a) { cout << "print(double a)" << endl; } void print(int a) { cout << "print(int a)" << endl; } int main() { print(1.1); print(1); return 0; }
執行結果如下:
print(double a)
print(int a)
請按任意鍵繼續. . .
//3.函數的參數順序不同 #include <iostream> using namespace std; void print(double a, int b) { cout << "print(double a, int b)" << endl; } void print(int b, double a) { cout << "print(int b, double a)" << endl; } int main() { print(1.1, 1); print(1, 1.1); return 0; }
執行結果如下:
print(double a, int b)
print(int b, double a)
請按任意鍵繼續. . .
上面就是支持函數重載的三種情況,緊接著看如下兩個函數是否構成函數重載?
int Add(int num1, int num2) { return num1 + num2; } double Add(int num1,int num2) { return num1 + num2; } int main() { return 0; }
我們一編譯,編譯器就會報如下錯誤:
通過上面的分析,我們可以發現是否構成函數重載隻與這些同名函數的形參列表(參數個數 或 類型 或 順序)有關,與函數的返回值的類型無關。因此返回值不同,不能構成函數重載,在調用時無法區分。
下面思考如下兩個函數是否構成函數重載?
void print(int a) { cout << "print()" << endl; } void print(int a = 0) { cout << "print(int a = 0)" << endl; }
我們一編譯,編譯器就會報如下錯誤:
因此函數參數缺省值不同,也不構成函數重載。
最後再看如下兩個函數是否構成函數重載?
void print(int a) { cout << "print()" << endl; } void print(int a = 0) { cout << "print(int a = 0)" << endl; }
很顯然上面兩個函數是構成函數重載的,我們編譯也沒有任何問題,但是我們不傳參調用就會出問題,比如print(),就會在調用時出現歧義。
2 函數重載原理
通過上面的學習,我們現在對函數重載的語法有瞭一定的認識和理解,緊接著我們帶著如下問題來分析一下函數重載的原理。
為什麼C++支持函數重載,而C語言不支持函數重載呢?
首先我們在Linux底下創建三個文件,來驗證上面的問題,如下:
//func.h #include <stdio.h> void f(); void f(int a); //func.c void f() { printf("f()\n"); } void f(int a) { printf("f(int a)\n"); } //test.c #include "func.h" int main() { f(); f(1); return 0; }
調用C的編譯器編譯test.c和func.c就會報如下錯誤:
因此,驗證瞭C語言不支持函數重載。因為編譯的時候 ,兩個重載函數,函數名相同,在func.o的符號表中存在歧義和沖突。其次,鏈接的時候也存在歧義和沖突,因為它們都是用函數名去標識和查找,而重載函數,函數名相同。
為瞭驗證上面的說法,我們屏蔽一個函數,調用C的編譯器編譯test.c和func.c,在linux底下會生成一個a.out的可執行程序,用objdump -S 來查看一下這個文件:
同理,我們把剛屏蔽的函數取消掉,由於C++是兼容C的,因此上面的程序我們可以用C++的編譯器去編譯,其結果如下
用objdump -S 來查看一下a.out:
這裡不難看出c++目標文件中的符號表中不是直接用函數名來標識和查找函數。而是引入瞭函數名修飾規則,不同編譯器下的函數名修飾規則不同。
g++的函數名修飾規則:_Z + 函數名長度 + 函數名 + 參數類型首字母。有瞭函數名修飾規則,隻要函數參數不同,在func.o符號表裡面重載的函數就不存在二義性和沖突瞭。
其次,鏈接的時候,test.o裡面的main函數去調用兩個重載函數時,去符號表裡面查找地址時也是明確的。
總結
本篇文章就到這裡瞭,希望能夠給你帶來幫助,也希望您能夠多多關註WalkonNet的更多內容