您好,登錄后才能下訂單哦!
這篇文章主要介紹了C++函數重載怎么定義使用的相關知識,內容詳細易懂,操作簡單快捷,具有一定借鑒價值,相信大家閱讀完這篇C++函數重載怎么定義使用文章都會有所收獲,下面我們一起來看看吧。
定義:同一個標識符在不同的上下文有不同的意義
用同一個函數名定義不同的函數
當函數名和不同的參數搭配時函數的含義不同
如下:
下面看一段代碼,感受一下:
#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); } int main(int argc, char *argv[]) { printf("%d\n", func(3)); printf("%d\n", func(4, 5)); printf("%d\n", func("D.T.Software")); return 0; }
下面為輸出結果:
函數重載至少滿足下面的一個條件:
參數個數不同
參數類型不同
參數順序不同
下圖所示就是參數的順序不同:
下面看一個函數默認參數遇上函數重載的實例程序:
#include <stdio.h> 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 argc, char *argv[]) { int c = func(1, 2); return 0; }
下面為輸出結果:
編譯報錯,因為模棱兩可。如果說調用第一個函數說的過去,因為符合函數默認參數規則,c 的值已經確定;調用第二個函數也符合常理,所以編譯不會通過。
將所有同名函數作為候選者
嘗試尋找可行的候選函數
精確匹配實參
通過默認參數能夠匹配實參
通過默認類型轉換匹配實參
匹配失敗
最終尋找到的候選函數不唯一,則出現二義性,編譯失敗。
無法匹配所有候選者,函數未定義,編譯失敗。
重載函數在本質上是相互獨立的不同函數
重載函數的函數類型不同
函數返回值不能作為函數重載的依據
函數重載是由函數名和參數列表決定的!!!
函數重載的本質是什么?下面通過一段代碼深入分析,編譯環境為VS2012。
#include "stdafx.h" #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; }
由C語言的知識可以知道,函數名就是函數的入口地址,所以輸出結果如下:
可以看到,兩個 add() 函數的入口地址不一樣,所以這兩個 add 是兩個不同的函數。
編譯器是如何看待這兩個 add() 函數的呢?下面來深入分析。先看一下編譯器產生的中間結果,在Test -> Debug -> Test.obj 文件中。
然后使用VS2012里面自帶的命令行工具查看 Test.obj 里面有什么東西。
上圖示為VS2012 命令行所在位置
輸入 dumpbin,如下:
這里只需要關系 SYMBOLS(符號表),符號表就是編譯器在編譯過程中根據源代碼所生成的一張表,這張表有程序的函數名變量等等。
輸入以下命令,其中 /symbols 后面為 Test.obj 所在的位置。
找到下面的地方,可以看到編譯器編譯 (int __cdecl add(int,int)) 時標識符為?add@@YAHHH@Z;而編譯器編譯(int __cdecl add(int,int,int)) 時標識符為?add@@YAHHHH@Z ,也就是說編譯器在編譯這兩個函數時已經把這兩個函數分別對待,盡管它們名字一樣,所以兩個 add() 函數的入口地址不一樣,這就很好理解了。
函數重載是 C++ 中引入的概念
函數重載用于模擬自然語言中的詞匯搭配
函數重載使得 C++ 具有更豐富的語義表達能力
函數重載的本質為相互獨立的不同函數
C++ 中通過函數名和函數參數確定函數調用
將重載函數名賦值給函數指針時
根據重載規則挑選與函數指針參數列表一致的候選者
嚴格匹配候選者的函數類型與函數指針的函數類型
下面看一段代碼:
#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); 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", add); return 0; }
編譯的時候會報錯,無法確定是哪個函數。
實際工程中C++和C代碼相互調用是不可避免的
C++編譯器能夠兼容C語言的編譯方式
C++編譯器會優先使用C++編譯的方式
extern 關鍵字能強制讓C++編譯器進行C方式的編譯
如下:
在 Linux環境下新建一個 9-2 文件夾,先在文件夾下新建 add.c 和 add.h 文件,如下:
add.c :
#include "add.h" int add(int a, int b) { return a + b; }
add.h :
int add(int a, int b);
通過 linux 命令 cd 進入 9-2 文件夾,再將 add.c 轉換成 add.o 文件,如下所示:
然后在 9-2 文件夾下建一個 main.cpp 文件,如下:
mian.cpp :
#include <stdio.h> #include "add.h" int main() { int c = add(1,2); printf("c = %d\n", c); return 0; }
對程序進行編譯,發現程序報錯,沒有定義 add() 函數,但是函數確實已經定義了,可以使用 linux 中的 nm 指令查看 add.o 里面的信息,打印出來的就是符號表信息,可以看到確實有 add 。
這個時候就需要使用 extern關鍵字強制讓C++編譯器進行C方式的編譯,所以 main.cpp就要修改成這樣:
#include <stdio.h> extern "C" { #include "add.h" } int main() { int c = add(1,2); printf("c = %d\n", c); return 0; }
這樣編譯就能通過了:
如果在 9-2 文件中新建一個 main.c 文件,main.c 里面的代碼 與 main.cpp 中的相同。
進行編譯,發現會報錯誤,因為 extern 關鍵詞寫法是 C++ 中的, C語言不支持該寫法。那有沒有一種寫法既能被 C語言編譯通過,又能讓 C++編譯通過呢?且看下面。
_cplusplus 是C++編譯器內置的標準宏定義
_cplusplus 的意義是確保C代碼以統一的C方式被編譯成目標文件
如下:
所以上述代碼可以寫作,main.c和 main.cpp 均為:
#include <stdio.h> #ifdef __cplusplus extern "C" { #endif #include "add.h" #ifdef __cplusplus } #endif int main() { int c = add(1, 2); printf("c = %d\n", c); return 0; }
這樣程序在 C語言和 C++ 的編譯環境下均能通過,如下:
注意事項
C++編譯器不能以C的方式編譯重載函數
編譯方式決定函數名被編譯后的目標名
C++編譯方式將函數名和參數列表編譯成目標名
C 編譯方式只將函數名作為目標名進行編譯
下面通過一個例子說明一下:
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; }
將該代碼編譯成目標文件,取名為 test.oo,然后通過 linux 中的 nm 命令查看 test.oo 中的東西,可以看到 test 符號表里面有兩個東西 T _Z3addii 和T _Z3addiii,這就是 add 函數被編譯過后的目標函數名,ii 表示兩個參數, iii 表示三個參數。
如果采用 C 方式編譯重載函數,代碼如下:
extern "C" { int add(int a, int b) // ==>add { return a + b; } int add(int a, int b, int c) // ==>add { return a + b + c; } }
下面為編譯結果,可以看到編譯報錯,說兩個 add() 函數沖突了。
關于“C++函數重載怎么定義使用”這篇文章的內容就介紹到這里,感謝各位的閱讀!相信大家對“C++函數重載怎么定義使用”知識都有一定的了解,大家如果還想學習更多知識,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。