C++內聯函數
代碼的重複導致臃腫的執行程序,一直讓很多程序員不勝其煩,而內聯函數提供了另一種選擇。編譯器將使用相應的函數代碼替換函數調用。因此,內聯函數的運行速度比常規函數稍快,但代價是需要佔用更多內存。
1 .內聯函數的使用
在函數聲明前加上關鍵字inline;
在函數定義前加上關鍵字inline。
示例如下:
#include
inline double square(double x){return x*x;}
int main()
{
using namespace std;
double a,b;
double c = 13.0;
a = square(5.0);
b = square(4.5+7.5);
cout<<<
cout<<
cout<<
cout<<
return 0;
}
}
程序輸出結果如下:
a=25,b=144
c=13
c square=169
now c=14
增加了 inline 關鍵字的函數稱爲“內聯函數”。內聯函數和普通函數的區別在於:當編譯器處理調用內聯函數的語句時,不會將該語句編譯成函數調用的指令,而是直接將整個函數體的代碼插人調用語句處,就像整個函數體在調用處被重寫了一遍一樣。
inline適用的函數有兩種,一種是在類內定義的成員函數,另一種是在類內聲明,類外定義的成員函數,對於這兩種情況inline的使用有一些不同:
(1)類內定義成員函數
這種情況下,我們可以不用在函數頭部加inline關鍵字,因爲編譯器會自動將類內定義的函數聲明爲內聯函數,代碼如下:
class temp{
public:
int amount;
//構造函數
temp(int amount){
this->amount = amount;
}
//普通成員函數,在類內定義時前面可以不加inline
void print_amount(){
cout << this-> amount;
}
}
從上面的代碼可以看出,在類內定義函數時,可以不加inline關鍵字,編譯器會自動將類內定義的函數(構造函數、析構函數、普通成員函數等)設置爲內聯,具有內聯函數調用的性質。
(2) 類內聲明函數,在類外定義函數
根據C++編譯器的規則,這種情況下如果想將該函數設置爲內聯函數,則可以在類內聲明時不加inline關鍵字,而在類外定義函數時加上inline關鍵字,代碼如下所示:
class temp{
public:
int amount;
//構造函數
temp(int amount){
this->amount = am
ount;
}
//普通成員函數,在類內聲明時前面可以不加inline
void print_amount()
}
//在類外定義函數體,必須在前面加上inline關鍵字
inline void temp:: print_amount(){
cout << amount << endl;
}
從上面代碼我們可以看出,類內聲明可以不用加上inline關鍵字,但是類外定義函數體時必須要加上,這樣才能保證編譯器能夠識別其爲內聯函數。
另外,我們可以在聲明函數和定義函數的同時寫inline,也可以只在函數聲明時加inline,而定義函數時不加inline。只要在調用該函數之前把inline的信息告知編譯系統,編譯系統就會在處理函數調用時按內聯函數處理。也就是說,上面說的幾種方法都可以實現一個內聯函數的定義,根據自己的需要來寫即可。
2 .內聯函數與宏定義的區別
C語言使用預處理器語句#define來提供宏。如下例所示:
#define SQUARE(X) X*X
宏定義時通過文本替換開實現的--X是參數的符號標記。
a = square(5.0);->a=5.0*5.0;
b = square(4.5+7.5);->b=4.5+7.5*4.5+7.5
d = square(c++);->d=c++*c++
可以看出,對於b,需要使用括號才能正常運算。
#define SQUARE(X) ((X)*(X))
對於c,卻仍遞增了兩次。
因此,宏定義和內聯函數存在本質的區別,轉換的時候應考慮是否轉換後功能是否正常。
3什麼時候使用內聯函數
如果執行函數代碼的時間比處理函數調用機制的時間長,則節省的時間佔比很小。若代碼執行時間很短,則內聯函數就可以節省函數調用的時間。
Tips
^當函數體比較小的時候, 內聯該函數可以令目標代碼更加高效. 對於存取函數以及其它函數體比較短, 性能關鍵的函數, 鼓勵使用內聯.
^但濫用內聯將導致程序變慢. 內聯可能使目標代碼量或增或減, 這取決於內聯函數的大小. 內聯非常短小的存取函數通常會減少代碼大小, 但內聯一個相當大的函數將戲劇性的增加代碼大小. 現代處理器由於更好的利用了指令緩存, 小巧的代碼往往執行更快。
^ 結論: 一個較爲合理的經驗準則是, 不要內聯超過 10 行的函數. 謹慎對待析構函數, 析構函數往往比其表面看起來要更長, 因爲有隱含的成員和基類析構函數被調用!
^另一個實用的經驗準則: 內聯那些包含循環或 switch 語句的函數常常是得不償失 (除非在大多數情況下, 這些循環或 switch 語句從不被執行).有些函數即使聲明爲內聯的也不一定會被編譯器內聯, 這點很重要; 比如虛函數和遞歸函數就不會被正常內聯. 通常, 遞歸函數不應該聲明成內聯函數.(遞歸調用堆棧的展開並不像循環那麼簡單, 比如遞歸層數在編譯時可能是未知的, 大多數編譯器都不支持內聯遞歸函數). 虛函數內聯的主要原因則是想把它的函數體放在類定義內, 爲了圖個方便, 抑或是當作文檔描述其行爲, 比如精短的存取函數.