日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

函数重载、引用再探、内联函数

發(fā)布時間:2023/12/13 编程问答 19 豆豆
生活随笔 收集整理的這篇文章主要介紹了 函数重载、引用再探、内联函数 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

文章目錄

  • 函數(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ī)則來編譯。


引用再探

引用的特性

  • 引用在定義的時候必須初始化(因為引用是某個對象的別名,所以必須初始化)
  • 一個對象可以有多個引用
  • 一旦引用一個實體,就不能再引用別的實體(有點類似指針的頂層const)
  • 引用的使用場景

  • 作為參數(shù)
  • struct A {int arr[1000000]; };void test(A& s1) {}

    假設(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; }
  • 作為返回值
  • int& Add(int a, int b) {int c = a + b;return c; }int main() {int& ret = Add(1, 2);Add(3, 4);cout << ret << endl;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ǔ)上又給他封裝了新的功能。

    引用和指針的不同點:

  • 引用在定義時必須初始化,指針沒有要求
  • 引用在初始化時引用一個實體后,就不能再引用其他實體,而指針可以在任何時候指向任何一個同類型 實體
  • 沒有NULL引用,但有NULL指針
  • 在sizeof中含義不同:引用結(jié)果為引用類型的大小,但指針始終是地址空間所占字節(jié)個數(shù)(32位平臺下占 4個字節(jié))
  • 引用自加即引用的實體增加1,指針自加即指針向后偏移一個類型的大小
  • 有多級指針,但是沒有多級引用
  • 訪問實體方式不同,指針需要顯式解引用,引用編譯器自己處理
  • 引用比指針使用起來相對更安全

  • 內(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ù)是一種用空間換時間的做法,省去了創(chuàng)建棧幀和壓棧的開銷,但也因此代碼很復(fù)雜和具有循環(huán)或遞歸之類的函數(shù)不適合作為內(nèi)聯(lián)函數(shù),就算聲明為內(nèi)聯(lián)函數(shù)編譯器也會自動將其忽略。
  • 內(nèi)聯(lián)函數(shù)不能聲明和定義分離,因為一旦聲明為內(nèi)聯(lián)函數(shù),在調(diào)用的時候就會直接展開,沒有了函數(shù)的地址,就無法將其鏈接到定義的部分。
  • 值得一提的是,內(nèi)聯(lián)函數(shù)與C語言中的宏函數(shù)有些類似,雖然宏的性能不錯,但是因為宏缺乏類型的安全檢查和無法調(diào)試(在預(yù)處理階段就進行了宏替換),在C++中宏函數(shù)被內(nèi)聯(lián)函數(shù)替代,宏常量定義被const取代。

    內(nèi)聯(lián)函數(shù)的好處

  • 較之等價的表達(dá)式更易于閱讀
  • 可以被其他應(yīng)用重復(fù)利用,省去了重新編寫的代價
  • 如需修改計算過程,顯然修改函數(shù)比先找到等價表達(dá)式所有出現(xiàn)的地方再逐一修改更容易。
  • 類的內(nèi)聯(lián)成員函數(shù)的聲明

    我們可以在類內(nèi)把inline作為聲明的一部分顯式地聲明成員函數(shù),同樣的,也能在類的外部用inline關(guān)鍵字修飾函數(shù)的定義(當(dāng)然在聲明和定義的地方同時說明inline也是合法,只是沒有必要)。


    constexpr函數(shù)

    概念

    能用于常量表達(dá)式的函數(shù)

    特征

  • 函數(shù)的返回類型及所有形參的類型都得是字面值類型
  • 函數(shù)體中必須有且只有一條return語句
  • 編譯器把對constexpr函數(shù)的調(diào)用替換成其結(jié)果值(constexpr函數(shù)被隱式地指定為內(nèi)聯(lián)函數(shù))
  • 函數(shù)體內(nèi)允許包含 運行時不執(zhí)行任何操作的語句
  • 允許返回一個非常量,應(yīng)用時編譯器會進行檢查。(constexpr不一定返回常量表達(dá)式)
  • 內(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)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。