函数重载、引用再探、内联函数
文章目錄
- 函數(shù)重載
- 為什么C++支持重載,C語言不支持呢?
- extern “C”
- 引用再探
- 引用的特性
- 引用的使用場景
- 引用和指針
- 引用和指針的不同點:
- 內(nèi)聯(lián)函數(shù)
- 什么是內(nèi)聯(lián)函數(shù)?
- 內(nèi)聯(lián)函數(shù)的特性
- 內(nèi)聯(lián)函數(shù)的好處
- 類的內(nèi)聯(lián)成員函數(shù)的聲明
- constexpr函數(shù)
- 概念
- 特征
- 內(nèi)聯(lián)函數(shù)和constexpr函數(shù)放在頭文件內(nèi)
函數(shù)重載
在同一個作用域下,對于相同的函數(shù)名,函數(shù)的參數(shù)類型不同,參數(shù)順序不同,參數(shù)的個數(shù)不同, 都可以形成函數(shù)的重載(參數(shù)名不同,返回值不同不形成重載)
函數(shù)的重載主要用于處理功能相同,形參類型不同的數(shù)據(jù)。
void test(int i, int j) {cout << "test" << endl; }void test(double i, int j) // 類型不同 {cout << "test" << endl; }void test(int j, double i) // 順序不同 {cout << "test" << endl; }void test(double i, int j, int k) // 個數(shù)不同 {cout << "test" << endl; }為什么C++支持重載,C語言不支持呢?
因為windows對函數(shù)重載的處理更加復(fù)雜,所以這里用linux下的gcc和g++來看更加直觀。
首先我們要知道,鏈接器看到有函數(shù)被調(diào)用的時候,就會到符號表中去查找對應(yīng)的函數(shù)名,來獲取函數(shù)的地址,再鏈接到一起
先看C語言是怎么處理的
通過反匯編我們可以看到,C語言并沒有對函數(shù)名進行處理,也就是說無論我們參數(shù)的個數(shù),參數(shù)的類型,參數(shù)的順序怎么修改,它只認(rèn)函數(shù)名,如果出現(xiàn)了第二個相同函數(shù)名的,就算重定義。
下面再看C++的:
這里可以看到,C++對函數(shù)名進行了處理,函數(shù)以_Z4開頭,接著是函數(shù)名,最后是所有參數(shù)的縮寫。
_Z是所有函數(shù)的前綴,4是函數(shù)名的字符個數(shù),例如第一個_Z4testii則代表函數(shù)名為test,具有四個字符,參數(shù)類型縮寫分別是ii。
這也就是為什么返回值不同和參數(shù)名不構(gòu)成重載的原因,它們不被作為對函數(shù)特征的處理。C++正是通過這種函數(shù)名修飾規(guī)則來實現(xiàn)函數(shù)的重載。
extern “C”
有時候我們在使用C++的時候,對于某些函數(shù),想讓它按照C的風(fēng)格來編譯,那么就在函數(shù)前加extern “C”,意思是告訴編譯器,將該函數(shù)按照C語言規(guī)則來編譯。
引用再探
引用的特性
引用的使用場景
假設(shè)我們存在一個超級大的結(jié)構(gòu)體,如果我們直接將結(jié)構(gòu)體傳過去的話,會產(chǎn)生一個臨時變量來將這個結(jié)構(gòu)體拷貝到形參中,這是極大的開銷,但如果我們使用引用的話,傳的只是一個別名而已,所有的操作還是在結(jié)構(gòu)體本身上進行的,但是需要注意的和上面一樣,如果我們要傳遞一個常量,就必須要在引用前加上const。
struct A {int arr[1000000]; };void test (const A& s1) {} int main(int argc, char const *argv[]) {const A a = {10,324,32};test(a);return 0; }對于這樣一個代碼,我們可能第一眼覺得ret會是3。
但是其實是7。
因為我們返回的是c的一個引用,但是c只存在于調(diào)用時的那個棧幀,調(diào)用結(jié)束后那個棧幀就會被銷毀,雖然銷毀后數(shù)據(jù)不會被清空,但是那片區(qū)域的訪問權(quán)限就會被放開,有可能會被下次調(diào)用的函數(shù)使用,也有可能會被其他的一個操作給使用,所以這是一種極為不安全的行為。
上面的7是第二次調(diào)用后修改了c的值。
所以,如果需要引用作為返回值,就必須保證出了函數(shù)作用域,返回的對象沒有歸還給系統(tǒng),仍然存在。
以值作為參數(shù)或者返回值時,在傳參和返回的時候,都會傳遞或返回原變量的一個臨時的拷貝,這樣的效率是非常低下的,尤其是數(shù)據(jù)特別大的時候,但如果使用引用作為參數(shù)的話,就不會有這樣的問題。
引用和指針
語法概念上:引用是對象的一個別名,沒有獨立的空間,和其引用的實體共用一個空間。
但我們發(fā)現(xiàn),引用其實和指針很像,它更像一個頂層const的指針,所以我們可以進入反匯編看看他們之間有沒有關(guān)系
int main() {int x = 5;int& y = x;int* z = &x;return 0; }
反匯編下我們可以看到,指針和引用在匯編下的實現(xiàn)是一模一樣的。
所以我們可以得出一個結(jié)論:引用是按照指針來實現(xiàn)的,在指針的基礎(chǔ)上又給他封裝了新的功能。
引用和指針的不同點:
內(nèi)聯(lián)函數(shù)
什么是內(nèi)聯(lián)函數(shù)?
用inline關(guān)鍵字修飾的函數(shù)就是內(nèi)聯(lián)函數(shù),在編譯時編譯器會將函數(shù)的代碼在調(diào)用內(nèi)聯(lián)函數(shù)的地方展開,減去了函數(shù)壓棧的開銷,提升程序運行的效率(犧牲空間換取時間)。
例如這樣一個簡單的代碼
如果我們直接調(diào)用它
在匯編下可以看到,他會創(chuàng)建一個新的棧幀,將參數(shù)3,4壓棧,然后計算完再返回結(jié)果
而如果在函數(shù)前面加上inline使其變?yōu)閮?nèi)聯(lián)函數(shù)
這時再看,就會發(fā)現(xiàn)它直接把函數(shù)的代碼在調(diào)用處直接展開,不會再創(chuàng)建新的棧幀。
內(nèi)聯(lián)函數(shù)的特性
值得一提的是,內(nèi)聯(lián)函數(shù)與C語言中的宏函數(shù)有些類似,雖然宏的性能不錯,但是因為宏缺乏類型的安全檢查和無法調(diào)試(在預(yù)處理階段就進行了宏替換),在C++中宏函數(shù)被內(nèi)聯(lián)函數(shù)替代,宏常量定義被const取代。
內(nèi)聯(lián)函數(shù)的好處
類的內(nèi)聯(lián)成員函數(shù)的聲明
我們可以在類內(nèi)把inline作為聲明的一部分顯式地聲明成員函數(shù),同樣的,也能在類的外部用inline關(guān)鍵字修飾函數(shù)的定義(當(dāng)然在聲明和定義的地方同時說明inline也是合法,只是沒有必要)。
constexpr函數(shù)
概念
能用于常量表達(dá)式的函數(shù)
特征
內(nèi)聯(lián)函數(shù)和constexpr函數(shù)放在頭文件內(nèi)
和其他函數(shù)不同,內(nèi)聯(lián)函數(shù)和constexpr可以在程序中多次定義(每一次展開就是一次定義)。但多個定義必須完全一致,基于這個原因,內(nèi)聯(lián)函數(shù)和constexpr函數(shù)通常定義在頭文件。
總結(jié)
以上是生活随笔為你收集整理的函数重载、引用再探、内联函数的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2022年办理银行卡为什么要证明,要保证
- 下一篇: 【精品计划 附录2】- 算法分析