1、什么是重載函數
同一個函數名定義不同的函數,當函數名相同,不同的參數搭配時含義不同。
例如:
#include <stdio.h> #include <string.h> int func(int x) { return x; } int func(int x,int y) { return x + y; } int func(const char *s) { return strlen(s); } int main(int argc, char *argv[]) { printf("Begin...\n"); printf("%d\n" ,func(1)); printf("%d\n" ,func(2,3)); printf("%d\n" ,func("abcdefg")); printf("End...\n"); return 0; }
運行結果:
Begin... 1 5 7 End...
上面代碼函數名相同,在C語言中是肯定會報錯的因為C語言不支持重載函數。而在C++中是不會報錯的。而且會根據參數 調用 對應的函數。
2、允許重載的條件是什么了?
2.1、參數類型不同
2.2、參數個數不同
2.3、參數順序不同
三個條件滿足其中一條即可滿足重載。
例如:下面代碼中的兩個 func 就滿足第 2.3條 參數順序不同
#include <stdio.h> #include <string.h> int func(const char *s ,int a) { return a; } int func(int a,const char *s ) { return strlen(s); } int main(int argc, char *argv[]) { printf("Begin...\n"); printf("%d\n",func("abc",2)); printf("%d\n",func(2,"abc")); printf("End...\n"); return 0; }
運行結果:
Begin... 2 3 End...
3、編譯器調用重載的准則:
3.1、將所有同名的函數作為候選
3.2、嘗試尋找可行的候選參數
3.2.1、精確匹配實參
3.2.2、通過默認參數能夠匹配實參
3.2.3、通過默認類型轉換匹配實參
匹配失敗的原因:
1、最終找出來的候選函數不唯一,出現二義性,編譯失敗。
例如:這里調用 printf("%d\n" func(1,2)); 的時候 就有兩個條件可以匹配所以編譯器也不知道應該調用那個函數。
#include <stdio.h> #include <string.h> int func(int a,int b) { return a + b; } int func(int a,int b,int c=10) { return a+b+c; } int main(int argc, char *argv[]) { printf("Begin...\n"); printf("%d\n" func(1,2)); printf("End...\n"); return 0; }
編譯結果:
test.cpp:18:25: error: call of overloaded ‘func(int, int)’ is ambiguous printf("%d\n" ,func(1,2)); ^ test.cpp:4:5: note: candidate: int func(int, int) int func(int a,int b) ^~~~ test.cpp:9:5: note: candidate: int func(int, int, int) int func(int a,int b,int c=10) ^~~~
2、無法匹配所有候選者,函數未定義,編譯失敗
4、函數重載的注意事項。
4.1、重載函數在本質上是相互獨立的函數
4.2、重載函數的函數類型不同
4.3、函數返回值不能作為函數重載的依據
函數重載是由函數名 和參數列表決定的。
5、重載與指針。
如下代碼:
#include <stdio.h> #include <string.h> int func(int a,int b) { return a + b; } int func(int a,int b,int c=10) { return a+b+c; } int func(const char *s) { return strlen(s); } typedef int (*Pfunc) (int a,int b); int main(int argc, char *argv[]) { printf("Begin...\n"); Pfunc P= func; int c = 0; c = P(1,2); printf("c = %d\n",c); printf("End...\n"); return 0; }
運行結果:
Begin... c = 3 End...
通過運行結果 可以清楚的看出, c = P(1,2); 其實就是調用到 int func(int a,int b) 這個函數。
使用 typedef int (*Pfunc) (int a,int b); 定義了一個 函數指針。
隨后通過 Pfunc P= func; 對函數指針 P進行初始化。
調用 c = P(1,2);
在這個過程中 C++通過 typedef int (*Pfunc) (int a,int b); 定義的類型使得 Pfunc P= func; 這個初始化能夠正確的匹配到 int func(int a,int b) 這個函數。
最終調用到 int func(int a,int b) 這個函數。
所以將重載函數名賦值給函數指針的時候
1、根據重載規則挑選與函數參數列表一致的候選者。
2、嚴格匹配候選者的函數類型與指針的函數類型。
上面說過 函數的 重載 與 返回值 無關,但是在通過函數指針指向重載函數的時候,C++會將返回值也作為編譯器判斷語法是否錯誤的依據。(這里就對應了上面第二點說的嚴格匹配候選者,包括匹配 返回值、函數名、函數參數)
注意:
1、只有在同一個作用域中函數才能重載。
2、編譯器選擇函數的 依據是 函數列表 與 函數參數
3、無法通過函數名直接得到重載函數的入口地址。(可以通過強制類型轉換的到函數的入口地址,需要給編譯器提供足夠多的信息選擇到對應函數)
例如:printf("%p\n",(int(*)(int,int))func);