C 複習第四章 內聯函式及預設引數

2021-10-08 23:22:41 字數 3968 閱讀 2014

為了保持預處理巨集的效率又增加安全性,而且還能像一般成員函式那樣可以在類裡訪問自如,c++引入了內聯函式(inline function).

內聯函式為了繼承巨集函式的效率,沒有函式呼叫時開銷,然後又可以像普通函式那樣,可以進行引數,返回值型別的安全檢查,又可以作為成員函式。

//問題一:

#define add(x,y) x+y

inline int add(int x,int y)

void test()

//問題二:

#define compare(x,y) ((x) < (y) ? (x) : (y))

int compare(int x,int y)

void test02()

//問題三:

/*預定義巨集函式沒有作用域概念,無法作為乙個類的成員函式,也就是說預定義巨集沒有辦法表示類的範圍。

一直到程式結束或者是#udefine

*/

在c++中,預定義巨集的概念是用內聯函式來實現的,而****內聯函式本身也是乙個真正的函式****。內聯函式具有普通函式的所有行為。唯一不同之處在於內聯函式會在適當的地方像預定義巨集一樣展開,所以不需要函式呼叫的開銷。因此應該不使用巨集,使用內聯函式。

在普通函式(非成員函式)函式前面加上inline關鍵字使之成為內聯函式。但是必須注意必須函式體和宣告結合在一起,否則編譯器將它作為普通函式來對待。

內聯函式的確占用空間,但是內聯函式相對於普通函式的優勢只是省去了函式呼叫時候的壓棧,跳轉,返回的開銷。我們可以理解為內聯函式是以****空間換時間****。

//注意必須函式體和宣告結合在一起,否則編譯器將它作為普通函式來對待。

inline void func(int a);

//以上寫法沒有任何效果,僅僅是宣告函式,應該如下方式來做:

inline int func(int a)

注意: 編譯器將會檢查函式引數列表使用是否正確,並返回值(進行必要的轉換)。這些是預處理器無法完成的。

為了定義內聯函式,通常必須在函式定義前面放乙個inline關鍵字。但是在類內部定義內聯函式時並不是必須的。****任何在類內部定義的函式自動成為內聯函式。****

class person

void printperson()

}//建構函式person,成員函式printperson在類的內部定義,自動成為內聯函式。

內聯函式並不是何時何地都有效,為了理解內聯函式何時有效,應該要知道編譯器碰到內聯函式會怎麼處理?

對於任何型別的函式,編譯器會將函式型別(包括函式名字,引數型別,返回值型別)放入到符號表中。同樣,當編譯器看到內聯函式,並且對內聯函式體進行分析沒有發現錯誤時,也會將內聯函式放入符號表。

當呼叫乙個內聯函式的時候,編譯器首先確保傳入引數型別是正確匹配的,或者如果型別不正完全匹配,但是可以將其轉換為正確型別,並且返回值在目標表示式裡匹配正確型別,或者可以轉換為目標型別,內聯函式就會直接替換函式呼叫,這就消除了函式呼叫的開銷。假如內聯函式是成員函式,物件this指標也會被放入合適位置。

型別檢查和型別轉換、包括在合適位置放入物件this指標這些都是預處理器不能完成的。

以下情況編譯器可能考慮不會將函式進行內聯編譯:

不能存在任何形式的迴圈語句

不能存在過多的條件判斷語句

函式體不能過於龐大

不能對函式進行取址操作

*內聯僅僅只是給編譯器乙個建議,編譯器不一定會接受這種建議,如果你沒有將函式宣告為內聯函式,那麼編譯器也可能將此函式做內聯編譯。乙個好的編譯器將會內聯小的、簡單的函式。*

c++在宣告函式原型的時可為乙個或者多個引數指定預設(預設)的引數值,當函式呼叫的時候如果沒有指定這個值,編譯器會自動用預設值代替。

void testfunc01(int a = 10, int b = 20)

//注意點:

//1. 形參b設定預設引數值,那麼後面位置的形參c也需要設定預設引數

void testfunc02(int a,int b = 10,int c = 10){}

//2. 如果函式宣告和函式定義分開,函式宣告設定了預設引數,函式定義不能再設定預設引數

void testfunc03(int a = 0,int b = 0);

void testfunc03(int a, int b){}

int main()

c++在宣告函式時,可以設定佔位引數。佔位引數只有引數型別宣告,而沒有引數名宣告。一般情況下,在函式體內部無法使用佔位引數。

void testfunc01(int a,int b,int)

//佔位引數也可以設定預設值

void testfunc02(int a, int b, int = 20)

int main()

*實現函式過載的條件:*

同乙個作用域

引數個數不同

引數型別不同

引數順序不同

//1. 函式過載條件

namespace a

void myfunc(int a)

void myfunc(string b)

void myfunc(int a, string b)

void myfunc(string b, int a)

}//2.返回值不作為函式過載依據

namespace b

//int myfunc(string b, int a){} //無法過載僅按返回值區分的函式

}

函式過載和預設引數一起使用,需要額外注意二義性問題的產生。

void myfunc(string b)

//函式過載碰上預設引數

void myfunc(string b, int a = 10)

int main()

函式返回值不作為過載條件:

當編譯器能從上下文中確定唯一的函式的時,如int ret = func(),這個當然是沒有問題的。然而,我們在編寫程式過程中可以忽略他的返回值。那麼這個時候,乙個函式為

void func(int x);另乙個為int func(int x); 當我們直接呼叫func(10),這個時候編譯器就不確定呼叫那個函式。所以在c++中禁止使用返回值作為過載的條件。

編譯器用不同的引數型別來修飾不同的函式名,比如void func(); 編譯器可能會將函式名修飾成_func,當編譯器碰到void func(int x),編譯器可能將函式名修飾為_func_int,當編譯器碰到void func(int x,char c),編譯器可能會將函式名修飾為_func_int_char我這裡使用」可能」這個字眼是因為編譯器如何修飾過載的函式名稱並沒有乙個統一的標準,所以不同的編譯器可能會產生不同的內部名。

void func****(){}*void func*(*int x*){}*void func*(*int x*,*char y*){}****

以上三個函式在linux下生成的編譯之後的函式名為:

_z4funcv //v 代表void,無引數_z4funci //i 代表引數為int型別_z4funcic //i 代表第乙個引數為int型別,第二個引數為char型別

第四章 函式

樣例1,不帶引數的函式 create or replace function helloworld return varchar2 is begin return 朋友,您好 end 呼叫函式 語句的呼叫 select helloworld from dual 第二種呼叫方法 pl sql塊 beg...

第四章 函式

知識點 1 函式 function 可接受輸入 執行指令 返回輸出的復合語句。呼叫函式,意味著提供輸入。每乙個輸入就是乙個引數,為函式提供引數稱之為 傳參 2 呼叫函式的語句 函式名 逗號分隔的引數 f x x 2 語句左側定義乙個函式 f 接受乙個引數 x 右側是函式具體定義,利用 x 中傳遞的引...

c 第四章複習題

8.設計乙個描述魚的結構宣告。結構中應當包括品種 重量 整數,單位為盎司 和長度 英吋 包括小數 答 struct fish 12 假設treacle是乙個包含10個元素的float陣列,請宣告乙個指向treacle的第乙個元素的指標,並使用該指標來顯示陣列的第乙個元素和最後乙個元素。答 float...