C++之inline內聯函數

@著作權歸作者所有:來自CSDN博客作者大鬍子的艾娃的原創作品,如需轉載,請註明出處https://blog.csdn.net/qq_43148810,否則將追究法律責任。
如有錯誤的地方歡迎指正,謝謝!

一、inline內聯函數特徵
1、相當於把內聯函數裏面的內容寫在調用內聯函數處;
2、相當於不用執行進入函數的步驟,直接執行函數體;
3、相當於宏,卻比宏多了類型檢查,真正具有函數特性;
4、函數內不能包含循環、遞歸、switch 等複雜操作;
5、在類聲明中定義的函數,除了虛函數的其他函數都會自動隱式地當成內聯函數。

二、inline內聯函數的使用

// 聲明1(加 inline,建議使用)
inline int functionName(int first, int secend,...);

// 聲明2(不加 inline)
int functionName(int first, int secend,...);

// 定義
inline int functionName(int first, int secend,...) {/****/};

// 類內定義,隱式內聯
class A {
    int doA() { return 0; }         // 隱式內聯
}

// 類外定義,需要顯式內聯
class A {
    int doA();
}
inline int A::doA() { return 0; }   // 需要顯式內聯

三、編譯器對 inline內聯函數的處理步驟
1、將 inline 函數體複製到 inline 函數調用點處;
2、爲所用 inline 函數中的局部變量分配內存空間;
3、將 inline 函數的的輸入參數和返回值映射到調用方法的局部變量空間中;
4、如果 inline 函數有多個返回點,將其轉變爲 inline 函數代碼塊末尾的分支(使用 GOTO)。

四、inline內聯函數的優缺點
1、優點
a、內聯函數同宏函數一樣將在被調用處進行代碼展開,省去了參數壓棧、棧幀開闢與回收,結果返回等,從而提高程序運行速度。
b、內聯函數相比宏函數來說,在代碼展開時,會做安全檢查或自動類型轉換(同普通函數),而宏定義則不會。
c、在類中聲明同時定義的成員函數,自動轉化爲內聯函數,因此內聯函數可以訪問類的成員變量,宏定義則不能。
d、內聯函數在運行時可調試,而宏定義不可以。

2、缺點
a、代碼膨脹。內聯是以代碼膨脹(複製)爲代價,消除函數調用帶來的開銷。如果執行函數體內代碼的時間,相比於函數調用的開銷較大,那麼效率的收穫會很少。另一方面,每一處內聯函數的調用都要複製代碼,將使程序的總代碼量增大,消耗更多的內存空間。
b、inline 函數無法隨着函數庫升級而升級。inline函數的改變需要重新編譯,不像 non-inline 可以直接鏈接。
c、是否內聯,程序員不可控。內聯函數只是對編譯器的建議,是否對函數內聯,決定權在於編譯器。
d、內聯函數的定義必須出現在對該函數的調用之前,因爲編譯器在對函數調用語句進行替換時,必須事先知道替換該語句的代碼是什麼。所以如果僅在聲明函數原型時加上關鍵字inline,並不能達到內聯效果。

五、虛函數(virtual)可以是內聯函數(inline)嗎?
參閱:http://www.cs.technion.ac.il/users/yechiel/c+±faq/inline-virtuals.html
1、虛函數可以是內聯函數,內聯是可以修飾虛函數的,但是當虛函數表現多態性的時候不能內聯。
2、內聯是在編譯器建議編譯器內聯,而虛函數的多態性在運行期,編譯器無法知道運行期調用哪個代碼,因此虛函數表現爲多態性時(運行期)不可以內聯。
3、inline virtual 唯一可以內聯的時候是:編譯器知道所調用的對象是哪個類(如 Base::who()),這隻有在編譯器具有實際對象而不是對象的指針或引用時纔會發生。

#include <iostream>  
using namespace std;
class Base
{
public:
    inline virtual void who()
    {
        cout << "I am Base\n";
    }
    virtual ~Base() {}
};
class Derived : public Base
{
public:
    inline void who()  // 不寫inline時隱式內聯
    {
        cout << "I am Derived\n";
    }
};

int main()
{
    // 此處的虛函數 who(),是通過類(Base)的具體對象(b)來調用的,編譯期間就能確定了,所以它可以是內聯的,但最終是否內聯取決於編譯器。 
    Base b;
    b.who();

    // 此處的虛函數是通過指針調用的,呈現多態性,需要在運行時期間才能確定,所以不能爲內聯。  
    Base *ptr = new Derived();
    ptr->who();

    // 因爲Base有虛析構函數(virtual ~Base() {}),所以 delete 時,會先調用派生類(Derived)析構函數,再調用基類(Base)析構函數,防止內存泄漏。
    delete ptr;
    ptr = nullptr;

    system("pause");
    return 0;
} 

建議:虛函數不要使用inline修飾。

更多內容請關注個人博客:https://blog.csdn.net/qq_43148810

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章