重載(Overload)c++
- 同一個標識符在不一樣的上下文有不一樣的意義
函數重載(Function Overload)函數
- 用同一個函數名定義不一樣的函數
- 當函數名和不一樣的參數搭配時函數的含義不一樣
int func(int x) { return x; } int func(int a, int b) { return a+b; } int func(const char* s) { return strlen(s); }
函數重載至少知足下面的一個條件:工具
int func(int a, const char* s) { return a; } int func(const char* s, int a) { return strlen(s); } // 能夠發生重載
當函數默認參數於函數重載發生做用測試
int func(int a, int b, int c = 0) { return a*b*c; } int func(int a, int b) { return a+b; } int main() { int c = func(1, 2); // Which one? // 直接報錯,特性參數衝突 return 0; }
編譯器調用重載函數的準則指針
- 將全部同名函數做爲候選者
嘗試尋找可行的候選函數code
- 精確匹配實參
- 經過默認參數可以匹配實參
- 經過默認類型轉換匹配實參
匹配失敗作用域
- 最終尋找到的候選函數不惟一,則出現二義性,編譯失敗
- 沒法匹配全部候選者,函數未定義,編譯失敗
函數重載的注意事項:編譯器
函數重載是由函數名
和參數列表
決定的,函數重載與返回值沒有關係string
證實函數重載是兩個不一樣的函數:io
#include <stdio.h> int add(int a, int b) // int(int, int) { return a + b; } int add(int a, int b, int c) // int(int, int, int) { return a + b + c; } int main() { printf("%p\n", (int(*)(int, int))add); printf("%p\n", (int(*)(int, int, int))add); // 發現函數的入口地址是不一樣的,因此是兩個不一樣的函數 return 0; } // 結果: // 00DF100A // 00DF100F // 意味着這兩個函數的入口地不一樣,反向證實了這兩個函數是不用的函數
也能夠經過vs自帶工具, dumpbin
命令,查看符號表SYMBOLS
034 00000000 SECT4 notype () External | ?add@@YAHHH@Z (int __cdecl add(int,int)) 035 00000000 SECT6 notype () External | ?add@@YAHHHH@Z (int __cdecl add(int,int,int))
編譯器獲得的這兩個函數的標識是不同的
重載函數的本質是兩個不一樣的函數
分析下面的函數將保存哪一個函數的地址
int func(int x) { return x; } int func(int a, int b) { return a + b; } int func(const char* s) { return strlen(s); } typedef int(*PFUNC)(int a); int c = 0; PFUNC p = func; c = p(1);
函數重載趕上函數指針,將重載函數名賦值給函數指針時:
函數類型包括了返回值類型
#include <stdio.h> #include <string.h> int func(int x) { return x; } int func(int a, int b) { return a + b; } int func(const char* s) { return strlen(s); } typedef int(*PFUNC)(int a); // 定義了一個函數指針 // typedef void(*PFUNC)(int a); // 返回值類型不匹配 // typedef double(*PFUNC)(int a); // 返回值類型不匹配 int main(int argc, char *argv[]) { int c = 0; PFUNC p = func; c = p(1); printf("c = %d\n", c); return 0; }
注意:
- 函數重載必然發生在同一個做用域中
- 編譯器須要用參數列表或函數類型進行函數選擇
- 沒法直接經過函數名獲得重載函數的入口地址
函數指針的時候採用匹配函數類型的方式進行選擇
#include <stdio.h> int add(int a, int b) // int(int, int) { return a + b; } int add(int a, int b, int c) // int(int, int, int) { return a + b + c; } int main() { // printf("%p\n", add); // 直接打印函數名地址,沒法匹配函數 printf("%p\n", (int(*)(int, int))add); // 這實際上是一個強制類型轉換,轉換成了一個函數指針類型,就會進行嚴格的函數類型匹配 printf("%p\n", (int(*)(int, int, int))add); return 0; }
實際工程中C++和C代碼相互調用是不可避免地,C++編譯器可以兼容C語言的編譯方式,可是會優先使用C++編譯器,extern
關鍵字能強制讓C++編譯器進行C方式的編譯
extern "C" { // do C-style compilation here }
extern "c"
只是針對C++來講的,C語言中不支持
怎麼樣保證C代碼不管在C++仍是C代碼中,都是用C編譯器編譯
__cplusplus
是C++編譯器內置的標準宏定義
__cplusplus
的意義:確保C代碼以統一的C方式被編譯成目標文件
這個宏能夠用來測試當前的編譯器是不是C++編譯器,而C語言內部沒有這個宏
#ifdef __cplusplus extern "C" { #endif // C-Style compilation #ifdef __cplusplus } #endif
在c代碼中也是能夠調用C++代碼的
注意:
- C++編譯器不能以C的方式編譯重載函數
編譯方式決定函數名被編譯後的目標名
- C++編譯方式將
函數名
和參數列表
編譯成目標名- C編譯方式只將
函數名
做爲目標名進行編譯
函數重載是C++對C的一個重要升級函數重載經過函數參數列表區分不一樣的同名函數
extern
關鍵字可以實現C和C++的相互調用編譯方式決定符號表中的函數名的最終目標名