<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
定義:同一個識別符號在不同的上下文有不同的意義
如下:
下面看一段程式碼,感受一下:
#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("%dn", func(3)); printf("%dn", func(4, 5)); printf("%dn", 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("%pn", (int(*)(int, int))add); printf("%pn", (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() 函數的入口地址不一樣,這就很好理解了。
將過載函數名賦值給函數指標時
下面看一段程式碼:
#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 = %dn", 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("%pn", add); printf("%pn", add); return 0; }
編譯的時候會報錯,無法確定是哪個函數。
如下:
在 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 = %dn", 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 = %dn", c); return 0; }
這樣編譯就能通過了:
如果在 9-2 檔案中新建一個 main.c 檔案,main.c 裡面的程式碼 與 main.cpp 中的相同。
進行編譯,發現會報錯誤,因為 extern 關鍵詞寫法是 C++ 中的, C語言不支援該寫法。那有沒有一種寫法既能被 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 = %dn", c); return 0; }
這樣程式在 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++函數過載內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45