c++從入門到放棄(五)函數基礎

​ 坑!c++

5.1 參數

int f(i++,i) //默認是不清楚先計算i仍是i++的,沒有規定實參的求值順序,可是,能夠假設從後往前計算,c語言中是這個過程 int f(int a,int) //形參名是可選的,通常狀況下須要一個名字,不提供也行,就是找不到這個形參 int f() {
    static int a=0;
    //這個局部靜態對象的生命週期是一直到整個進程結束!進程!
    //未顯式初始化則默認初始化爲0(內置類型)
}
int f(int ,int);
	//聲明裏面不必定須要形參名,注意是聲明!
	//函數三要素:返回類型(不寫其實默認爲int),函數名,形參類型
int f(int &a,int &b) //傳引用,可修改 //可是不能夠傳一個字面值,好比f(1,2),引用類型不能夠初始化爲字面值 int f(const int &a,const int &b) //這就能夠了。。。。f(1,2)沒有問題 //使用引用能夠避免拷貝,特別大的字符串的時候! //傳遞數組的時候,實際上傳遞的是數組的指針 //多維數組就不說了 //若是有問題,想一想這樣初始化這個形參是否會出現問題 複製代碼

若是不清楚形參的數量,可使用省略符形參數組

void foo(int a,...) void foo(...) 複製代碼

5.2 返回值

在含有return語句的循環後面應該也有一條return語句,若是沒有的話就是錯誤的,若是編譯器沒有發現這個錯誤,則運行時的行爲就是未定義的。函數

for(int i=0;i<n;i++)
    if(i>8)
        return;
return;		//必須寫以防止最後不返回
複製代碼

不要返回局部對象的引用或者指針,局部變量使用的空間在函數結束後是會被釋放的,因此不能夠返回局部變量的指針或者引用。可是返回局部變量的值是能夠的,由於使用的是拷貝的數據。ui

const string &manip() {
    string ret;
    if(!ret.empty())
        return ret;	//錯誤,返回局部變量的引用
    else
        return "abv";	//錯誤,這是一個局部臨時量,在函數結束的時候同樣會被清空空間
}
複製代碼

返回類類型或者引用,指針之類的函數,可使用函數調用的結果訪問其成員spa

auto z=shorterString(s1,s2).size();
//返回一個引用類型的函數能夠當作左值
char &get_val(string &s,int x) {return s[x];}
int main() {
    get_val(s,x)=1;	//直接當作左值修改
}
複製代碼

也可使用列表初始化返回指針

return {1,2,3}	//通常用來返回容器類型
複製代碼

5.3 重載

​ 若是同一做用域內的幾個函數名字相同可是形參列表不一樣(形參數量形參類型),則稱之爲重載函數。code

注意:main函數是不能重載的對象

int fun(int a,int b);
int fun(int a) int fun(char c) int fun(int c) //這就不是重載 int fun(int) //這也不是重載 複製代碼

​ 注意,函數參數是不承認頂層const的,因此默認頂層const加不加都同樣。生命週期

int fun(int a);
int fun(const int a);		//不能夠,頂層const

int fun(int *a);
int fun(int * const a);		//不能夠,頂層const

//若是形參是某種類型的指針或者引用,則經過區分其指向的是常量對象仍是很是量對象能夠實現函數重載,此時const是底層的
int fun(int &);
int fun(const int &);		//能夠重載,底層const
int fun(int *);
int fun(const int *);		//能夠重載,底層const
複製代碼

​ 注意須要避免函數重載的二義性!進程

​ 在不一樣的做用域中沒法重載函數!

5.4 特殊特性

​ 能夠爲函數形參賦值默認實參(在聲明中賦值)

int fun(int a,int b,int c=1);
//能夠爲一個或者多個形參賦值默認值,可是,一旦一個形參賦值了,則後面的形參都必須有默認實參
int fun(int a,int b=1,int c);		//沒法分辨fun(1,2)的二義性
//注意沒法修改一個已經存在的默認值
int fun(int ,int ,int c=2);			//錯誤
//可是能夠添加默認實參
int fun(int a,int b=2,int c=1);		//正確

##函數調用時實參按其位置解析,默認實參負責填補函數調用缺乏的尾部實參
int fun(string a="123",int a=1,int b=2);
fun(,2,3);		//錯誤,默認補充尾部默認參數,想修改哪一個那前面的都不能跳過!
    			//只能忽略尾部的實參
fun("1",2+1);	//假如想修改b這個程序會和預期不符,因此要消除二義性
複製代碼

​ 內聯函數,能夠避免函數調用的開銷,不會進入到函數的地址區,而是經過編譯器直接將函數代碼"粘貼"到對應位置,因此不適用於大型的函數,只適用於小型的,頻繁調用的函數。

inline int f(int a,int b) {return a>b?a:b;}
cout<<f(1,2)<<endl;
//等價於
cout<<1>2?1:2<<endl;
複製代碼

​ assert預處理宏

assert(expr)
    //表達式爲假則輸出信息並終止程序的運行
    //爲真則什麼也不作
複製代碼

5.5 函數匹配

具體操做以下

void f();
void f(int);
void f(int,int);
void f(double,double=3.14);

f(5.6);

(1)肯定候選函數
		1.與被調用的函數重名
		2.其聲明在調用點可見
//無淘汰
(2)肯定可行函數
		1.形參數量與本次調用提供的實參數量相等(考慮默認參數但是可行的)
		2.每一個參數的類型與對應的形參類型相同,或者能轉換成形參類型
//淘汰第1,3
//若是這步未找到可行函數,編譯器會報無匹配函數錯誤3)尋找最佳匹配
		尋找形參類型與實參類型最匹配的那個函數
		最佳匹配等級:
			1.精確匹配
					實參類型和形參類型相同
					實參從數組類型或函數類型轉換成對應的指針類型
					向實參添加頂層const或者從實參中刪除頂層const
			2.經過const轉換實現匹配(底層const3.經過類型提高實現的匹配
			4.經過算術類型轉換或指針轉換實現的匹配
			5.經過類類型轉換實現的匹配
	(若是重載函數的區別只是多了個底層const的話,將從函數調用的實際參數類型(常量或者很是量)來判斷)
	多個形參的函數匹配
    	1.該函數每一個實參的匹配都不劣於其餘可行函數須要的匹配
    	2.至少有一個實參的匹配優於其餘可行函數提供的匹配
    若是檢查了以後沒有找到惟一的一個函數脫穎而出,則編譯器報告二義性調用的信息。
 //f(42,2.56)
 //典型的二義性錯誤
複製代碼

5.6 函數指針

​ 函數指針指向的是函數不是對象。

int max(int a,int b);
//聲明一個能夠指向該函數的指針,只須要用指針替換函數名便可
int (*p)(int ,int);
//將函數賦值給函數指針的時候能夠忽略取地址符
p=max;
p=&max;		//加不加都同樣
//調用函數指針指向的函數的時候用不用解引用指針也同樣
cout<<p(1,2)<<endl;
cout<<(*p)(1,2)<<endl;
//能夠爲函數指針賦值0或者nullptr表示沒有指向任何位置
//當使用重載函數的時候,上下文必須清晰的界定到底使用的是哪一個函數,不能夠一對多
複製代碼
相關文章
相關標籤/搜索