<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                [TOC] # 簡介 在c中我們經常把一些短并且執行頻繁的計算寫成宏,而不是函數,這樣做的理由是為了執行效率,宏可以避免函數調用的開銷,這些都由預處理來完成。 但是在c++出現之后,使用預處理宏會出現兩個問題: * 第一個在c中也會出現,宏看起來像一個函數調用,但是會有隱藏一些難以發現的錯誤。 * 第二個問題是c++特有的,預處理器不允許訪問類的成員,也就是說預處理器宏不能用作類類的成員函數。 為了保持預處理宏的效率又增加安全性,而且還能像一般成員函數那樣可以在類里訪問自如,c++引入了內聯函數(inline function). 內聯函數為了繼承宏函數的效率,沒有函數調用時開銷,然后又可以像普通函數那樣,可以進行參數,返回值類型的安全檢查,又可以作為成員函數。 # 預處理宏的缺陷 預處理器宏存在問題的關鍵是我們可能認為預處理器的行為和編譯器的行為是一樣的。當然也是由于宏函數調用和函數調用在外表看起來是一樣的,因為也容易被混淆。但是其中也會有一些微妙的問題出現: 問題一: ~~~ #define ADD(x,y) x+y inline int Add(int x,int y){ return x + y; } void test(){ int ret1 = ADD(10, 20) * 10; //希望的結果是300 int ret2 = Add(10, 20) * 10; //希望結果也是300 cout << "ret1:" << ret1 << endl; //210 cout << "ret2:" << ret2 << endl; //300 } ~~~ 問題二: ~~~ #define COMPARE(x,y) ((x) < (y) ? (x) : (y)) int Compare(int x,int y){ return x < y ? x : y; } void test02(){ int a = 1; int b = 3; //cout << "COMPARE(++a, b):" << COMPARE(++a, b) << endl; // 3 cout << "Compare(int x,int y):" << Compare(++a, b) << endl; //2 } ~~~ 問題三: 預定義宏函數沒有作用域概念,無法作為一個類的成員函數,也就是說預定義宏沒有辦法表示類的范圍。 # 內聯函數 ## 內聯函數基本概念 在c++中,預定義宏的概念是用內聯函數來實現的,而內聯函數本身也是一個真正的函數。內聯函數具有普通函數的所有行為。唯一不同之處在于內聯函數會在適當的地方像預定義宏一樣展開,所以不需要函數調用的開銷。因此應該不使用宏,使用內聯函數。 * 在普通函數(非成員函數)函數前面加上inline關鍵字使之成為內聯函數。但是必須注意必須函數體和聲明結合在一起,否則編譯器將它作為普通函數來對待。 ~~~ inline void func(int a); ~~~ 以上寫法沒有任何效果,僅僅是聲明函數,應該如下方式來做: ~~~ inline int func(int a){return ++;} ~~~ ~~~ inline void mycompare(int a, int b) { int rel = a < b ? a : b; cout << "結果是: " << rel << endl; } int main() { mycompare(1, 2); system("pause"); return EXIT_SUCCESS; } ~~~ 注意: 編譯器將會檢查函數參數列表使用是否正確,并返回值(進行必要的轉換)。這些事預處理器無法完成的。 內聯函數的確占用空間,但是內聯函數相對于普通函數的優勢只是省去了函數調用時候的壓棧,跳轉,返回的開銷。我們可以理解為內聯函數是以空間換時間。 ## 類內部的內聯函數 為了定義內聯函數,通常必須在函數定義前面放一個inline關鍵字。但是**在類內部定義內聯函數時并不是必須的。任何在類內部定義的函數自動成為內聯函數。** ~~~ class Person{ public: Person(){ cout << "構造函數!" << endl; } void PrintPerson(){ cout << "輸出Person!" << endl; } } ~~~ 構造函數Person,成員函數PrintPerson在類的內部定義,自動成為內聯函數。 ## 內聯函數和編譯器 內聯函數并不是何時何地都有效,為了理解內聯函數何時有效,應該要知道編譯器碰到內聯函數會怎么處理? 對于任何類型的函數,編譯器會將函數類型(包括函數名字,參數類型,返回值類型)放入到符號表中。同樣,當編譯器看到內聯函數,并且對內聯函數體進行分析沒有發現錯誤時,也會將內聯函數放入符號表。 當調用一個內聯函數的時候,編譯器首先確保傳入參數類型是正確匹配的,或者如果類型不正完全匹配,但是可以將其轉換為正確類型,并且返回值在目標表達式里匹配正確類型,或者可以轉換為目標類型,內聯函數就會直接替換函數調用,這就消除了函數調用的開銷。假如內聯函數是成員函數,對象this指針也會被放入合適位置。 類型檢查和類型轉換、包括在合適位置放入對象this指針這些都是預處理器不能完成的。 # 限制 c++內聯編譯會有一些限制,以下情況編譯器可能考慮不會將函數進行內聯編譯: * 不能存在任何形式的循環語句 * 不能存在過多的條件判斷語句 * 函數體不能過于龐大 * 不能對函數進行取址操作 **內聯僅僅只是給編譯器一個建議,編譯器不一定會接受這種建議,如果你沒有將函數聲明為內聯函數,那么編譯器也可能將此函數做內聯編譯。一個好的編譯器將會內聯小的、簡單的函數。** 盡管大多數教科書中在函數聲明和函數定義處都增加了 inline 關鍵字,但我認為 inline 關鍵字不應該出現在函數聲明處。這個細節雖然不會影響函數的功能,但是體現了高質量 C++ 程序設計風格的一個基本原則:聲明與定義不可混為一談,用戶沒有必要、也不應該知道函數是否需要內聯。 **更為嚴格地說,內聯函數不應該有聲明,應該將函數定義放在本應該出現函數聲明的地方,這是一種良好的編程風格。 ** 在多文件編程中,我們通常將函數的定義放在源文件中,將函數的聲明放在頭文件中,希望調用函數時,引入對應的頭文件即可,我們鼓勵這種將函數定義和函數聲明分開的做法。但這種做法不適用于內聯函數,將內聯函數的聲明和定義分散到不同的文件中會出錯,請看下面的例子 main.cpp ~~~ #include <iostream> using namespace std; //內聯函數聲明 void func(); int main(){ func(); return 0; } ~~~ module.cpp ~~~ #include <iostream> using namespace std; //內聯函數定義 inline void func(){ cout<<"inline function"<<endl; } ~~~ 上面的代碼能夠正常編譯,但在鏈接時會出錯。func() 是內聯函數,編譯期間會用它來替換函數調用處,編譯完成后函數就不存在了,鏈接器在將多個目標文件(`.o`或`.obj`文件)合并成一個可執行文件時找不到 func() 函數的定義,所以會產生鏈接錯誤。 內聯函數雖然叫做函數,在定義和聲明的語法上也和普通函數一樣,但它已經失去了函數的本質。函數是一段可以重復使用的代碼,它位于虛擬地址空間中的代碼區,也占用可執行文件的體積,而內聯函數的代碼在編譯后就被消除了,不存在于虛擬地址空間中,沒法重復使用 聯函數看起來簡單,但是有很多細節需要注意,從代碼重復利用的角度講,內聯函數已經不再是函數了。我認為將內聯函數作為帶參宏的替代方案更為靠譜,而不是真的當做函數使用。 **在多文件編程時,我建議將內聯函數的定義直接放在頭文件中,并且禁用內聯函數的聲明(聲明是多此一舉** # 內聯函數定義在類外部 ~~~ class Student{ public: char *name; int age; float score; void say(); //內聯函數聲明,可以增加 inline 關鍵字,但編譯器會忽略 }; //函數定義 inline void Student::say(){ cout<<name<<"的年齡是"<<age<<",成績是"<<score<<endl; } ~~~ 這樣,say() 就會變成內聯函數。 這種在類體外定義 inline 函數的方式,必須將類的定義和成員函數的定義都放在同一個頭文件中(或者同一個源文件中),否則編譯時無法進行嵌入(將函數代碼的嵌入到函數調用出)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看