茂易網(wǎng)站建設(shè)鏈接購買平臺
C++相較于C語言來說,重載是一重大特性,讓我們一起簡單的回顧一下重載那些事
傳送門
- 函數(shù)重載是什么
- 為什么有函數(shù)重載
- 函數(shù)重載是如何實現(xiàn)的
- 總結(jié)
函數(shù)重載是什么
函數(shù)重載:是函數(shù)的一種特殊情況,C++允許在同一作用域中聲明幾個功能相似的同名函數(shù)
這些同名函數(shù)的形參列表(參數(shù)個數(shù)or類型or順序)必須不同
為什么有函數(shù)重載
通常用來處理功能類似數(shù)據(jù)類似的場景,簡而言之,為方便使用.
或者說發(fā)明C++的大佬們在沒有C++使用C語言編程時日積月累的經(jīng)驗吧()
函數(shù)重載是如何實現(xiàn)的
我們常說C++是C語言的超集,是兼容C語言的一門高級編程語言.那我們有沒有想過這么一個問題:為什么C++支持函數(shù)重載,而C語言不支持函數(shù)重載?
這也是寫這篇文章的目的所在
在C和C++中,應(yīng)該程序要運行起來,要經(jīng)歷:預(yù)處理、編譯、匯編、鏈接
下面我們借助Linux中g(shù)cc來理解一下這些過程
首先我們在Linux下創(chuàng)建以下文件
注: .cc也是cpp文件
這里采用了VScode遠(yuǎn)端連接的方法編輯(防止有人問為什么不像vim或者nano)
Linux下,gcc是C語言的編譯器,g++是C++的編譯器
以下是一個簡單的運行方法(看不懂的家人可以跳過,不是重點)
首先
預(yù)處理的工作大致有 頭文件展開、宏替換、條件編譯、去掉注釋.
即代碼層面上的處理后,只保留需要執(zhí)行的部分.產(chǎn)生后綴為**.i**預(yù)處理文件.
編譯大致有檢查語法,生成匯編代碼.由**.i文件產(chǎn)生后綴為.s**匯編文件.
(像這樣)
匯編即把像上圖一樣的匯編代碼轉(zhuǎn)化成二進(jìn)制的機器碼供CPU讀取.由**.s文件生成.o**后綴的目標(biāo)文件.
鏈接找到調(diào)用函數(shù)的地址并鏈接對應(yīng),合并到一起
我們首先要大致明白,函數(shù)在調(diào)用時,匯編代碼中都會有一個call指令來叫一下這個函數(shù)的地址
這里又牽扯到了符號表
鏈接時就會查詢符號表,符號表里記錄了函數(shù)與其地址的映射關(guān)系,即可以通過call地址的方式來找到函數(shù)并調(diào)用,但vs中的匯編代碼經(jīng)過修飾,展示并不直觀
我們借助Linux查看一下程序運行產(chǎn)生的符號標(biāo)識
我們找到了一些特定標(biāo)識,其實這些就可以看作是符號表內(nèi)函數(shù)地址與函數(shù)名,且與代碼對應(yīng).
我們仔細(xì)觀察可以發(fā)現(xiàn),每個函數(shù),嚴(yán)格一點我們稱之為重載函數(shù)之間地址是不相同的,他們的函數(shù)名也不相同.
他們的命名好像存在一種規(guī)則,有函數(shù)名的同時參數(shù)類型的首字符存在于函數(shù)名中!!!
每個平臺下規(guī)則不同,規(guī)則問題不用糾結(jié)
至少在這里,是**_Z 函數(shù)名長度 函數(shù)名 類型首字母**(指正類型會加一個i,如int* 即 ii)
這是不是意味著,重載函數(shù)的參數(shù)順序不同,類型不同,個數(shù)不同,就意味著編譯器底層會對其生產(chǎn)一個獨一無二的單獨的函數(shù)名和不同的地址,可以認(rèn)為從根本意義是他們不是同一個函數(shù)(可以這樣理解).
然后來觀察一下C語言
顯而易見的,底層并沒有對名稱進(jìn)行修飾!!!
C++的編譯器會將函數(shù)名在底層進(jìn)行修飾,形成獨一無二的名稱與地址,從而實現(xiàn)函數(shù)重載,但是C語言沒有.
所以C++支持函數(shù)重載,但C語言不支持.
從而引出了一個重要問題:C語言和C++互相調(diào)用的鴻溝
編譯器底層將C++的函數(shù)名進(jìn)行了修飾,C語言在查詢符號表時找不到函數(shù).反之亦然
編譯器底層沒有將C語言的函數(shù)名進(jìn)行修飾,C++在查詢符號表時找不到函數(shù)
解決方法:extern “c”,通常借助宏判斷.
總結(jié)
淺談重載,希望能幫助大家對重載有更深的認(rèn)識.
碼字不易,期待三連~~
有建議歡迎提出哦~~