c++回爐-函數

函數

void func(){return;}  //return後面不能接內容,或者沒有return.  在void函數中,return用於提前結束函數,否則在右大括號處結束
type func(){return value;}  //value到type有一步強制類型轉換; 返回值不可以數組,可以是指針,基本類型,類對象。
string func(){return "nihao!"} //返回常量
int func(int arr[], int n);       int myarray[10];    func(myarray, 10);  int arr[]和int *只有在函數頭裏面纔等價。
int func(const int arr[], int n);    //保證數組中的數據不能通過指針變量arr被改變
int func(int* start, int* end);  //數組可以通過起始地址加元素個數或者區間來傳遞

int n=5;  int* p=&n;  int** q=&p;   //q就是一個二級指針
const char* arrmonth[]={'Jan', 'Feb'};
const char** p = arrmonth; 
cout<<*(p+1)<<endl;    //輸出Feb

const int** pp2;	int* p1;   const int n=123;  
pp2 = &p1; //pp2->p1->data   =>   **pp2->data  ,  這句就是pp2指向的data跟p1指向的是同一個
*pp2 =&n;   //*pp2變成一級指針,指針指向n, 所以p1也指向了n
*p1=10;  //通過p1解引用改變了n的值,但是n是const, 所以普通指針可以複製給const指針這個命題不適合多級指針

void fun(int (*ar)[4], int row);  //二維數組做函數參數,4在函數體內是有效的
void fun(int ar[][4], int row);   //第二個參數爲二維數組的行數, 4在函數中可以使用
void fun(int arr[3][4]);   //只能接受3行4列的二維數組作爲形參
void fun(int **arr, int row, int column);  //指出行列
int array[100][5];		fun(array, 50);   //對前50行進行處理, 調用都是隻傳數組名

void alloc_mem(int**& arr, int row, int column){   //arr是二維指針的引用,相當於三維指針
	arr = (int**)malloc(row*sizeof(int*));   //二維數組是二維指針,第一維裏面存的是指針
	a[0] = (int*)malloc(row*column*sizeof(int));    //一次分配完整,內存連續
	for(int i=1; i<row; i++){  //處理各行指針的指向
		a[i] = a[i-1] + column;
	}
}
int** alloc_mem(int row, int column){
	
	return 
}

const double* (*pf)(const double*, int) = f1;   //聲明函數指針的同時進行初始化
const double* (*pf[3])(const double*, int) = {f1, f2, f3};  //包含三個函數指針的數組pf
typedef const double* (*pf)(const double*, int);    pf  obj1;  //pf是一種類型

//實參與引用形參不匹配時候的臨時變量
double fun(const double& ra){}
fun(arr[2]);   //double arr[10];   ra就是arr[2]				正常引用綁定
fun(rd);  //double& rd = side;  ra就是side				正常引用綁定
fun(*pd);   // double* pd = &side;  ra就是side			正常引用綁定
fun(edge);   //long edge = 5L;    ra指向的是一個匿名臨時變量,臨時變量只在函數調用期間存在。
fun(7.0);     //    ra指向的是一個匿名臨時變量,臨時變量只在函數調用期間存在。

//右值引用, 相比於右值引用,以前的就叫左值引用
double&&  re = std::sqrt(36.0);	cout<<re;   //得到6.0
double&& rf = 2.5;	std::cout<<rf;  //得到2.5

fre&  accumulate(fre& target, const fre& source){
	return target;    //因爲函數原型是fre&,所以這裏返回的是target的引用
}
void display(const fre& t);     display(accumulate(tem, tom));    //相當於display(tem), tem-target-t   都是引用傳遞。
accumulate(tup, temo) = tom;   //返回引用加不加const的區別
fre temp = accumulate(tup, temo);    //前一種,因爲是引用,指向可修改的內存塊,所以可以作爲左值,後面加了const,只能作爲右值了。

//函數重載
float fun(int a);		double fun(int a);    //不算是重載,因爲cout<<fun(5);  編譯器不知道調用哪一個
float fun(int a);     float fun(int& a);   //不是重載,同理,fun(5)無法確定調用哪一個
float fun(int& a);   float fun(int&& a);    //是重載,一個是左值引用,一個是右值引用

//函數模板重載
template <typename T>
void fun(T& a, T& b);
template<typename T>
void fun(T* a, T* b, int n);  	//是一個新的模板

//模板的具體化
template<typename T>
void fun(T& a, T& b);			//函數模板,調用時候兩個參數必須類型一致,否則編譯不過##1##
template<>
void fun<job>(job& a, job& b);   //特例化成T--job , 又叫具體化
template<>
void fun(job& a, job& b);   //第二種形式, 調用時候,優先匹配特例化的形式

template	void fun<int>(int& a, int& b);   //實例化的提前聲明
cout<<fun<double>(a, b);   //顯示實例化

//##1##直接調用函數屬於隱式實例化, 顯示實例化
fun<int>(a, b);   int a=4, float b=4.5;   //錯的還是不行????

//decltype用法:   decltype(expression)  var;
template<typename T1, typename T2>
void add(T1 x, T2 y) {   ?  xy = x + y; }    //因爲x,y是兩種類型,所以xy不知道該用什麼類型
void add(T1 x, T2 y) { decltype(x+y) xy = x+y; }   //用decltype來推測出x+y的類型。
//expression可以分爲:帶括號的左值,不帶括號的左值,函數,
decltype(len(3))   w;   //不回去執行len(3), 而是查看函數原型的返回值。
decltype(x) v;   // double &  x=y;    v就表示double &
decltype((p)) v;  //int p =4;    v就表示 int&  ,  decltype(p)  v;   v表示int

//如果不能推斷x+y的類型怎麼辦?
template<typename T1, typename T2>
?  add(T1 x, T2 y) {return x+y; }    ###1
template<typename T1, typename T2>         //
auto add(T1 x, T2 y)-> decltype(x+y) {return x+y; }    ###2
//###1中不能用decltype(x+y)替換?, 原因是:x, y是函數參數,返回值不可見,脫離了函數作用域
//###2中,用auto作爲了佔位符,把decltype(x+y)用->移到參數列表後面,這樣函數內部可見, 編譯器就可以把auto推測成decltype(x+y)

//例子
Time sum(Time& t1, Time& t2){
  Time sum;		sum.m=t1.m+t2.m   sum.h=t1.h+t2.h+sum.m/60;   sum.m %=60;   return sum;
} //沒有運算符重載,導致效率上很多浪費
Time Time::operator+(const Time& t) const{   //const函數的原因是修改的是局部Time的data
  Time sum;		sum.m=t1.m+t2.m   sum.h=t1.h+t2.h+sum.m/60;   sum.m %=60;   return sum;
}   //不能級聯  比如t4=t1+t2+t3,    t4=t1.operator+(t2.operator+(t3));    返回引用的話就可以級聯。

void display(const Stone& st, int n){		//Stone::Stone(double);  單個參數的構造函數 
  for(int i=0; i<n; i++) cout<<st.show();
}
display(575,2);  //編譯器先找Stone(int)構造函數,沒找到,找int可以隱式轉換的類型的構造函數Stone(double), int-->double然後轉化成Stone對象

using屬於編譯指令。
函數原型是函數與編譯器的接口,原型告訴編譯器函數的返回值,參數類型,數量。
函數返回值類型的作用,告訴調用函數到制定位置讀取多少字節的數據,這個數據就是被調用函數的返回值。
函數在接受不同類型實參的時候會有一步強制類型轉換。比如double形參接受了一個int實參。
函數形參接受實參值得過程是值傳遞。c++函數參數都是按值傳遞進行的,除了引用形參。
對數組名使用sizeof得到整個數組的大小;對數組名使用&得到的是整個數組的內存塊的起始地址;數組名錶示數組第一個元素的地址;
函數參數傳遞指針時候,值傳遞的是指針的值,引用傳遞的是指針的值所指向的數據。
stl中“超尾”的概念:標識數組結尾的參數指向數組最後一個元素後面的指針
二級指針:指向指針的指針。
void func(const double ar[], int n); 一個實參double* arr[]={…}; 形參對應位置不能加const. 爲什麼呢?因爲二級指針下命題不成立。編譯invalid conversion from ‘int**’ to ‘const int**’
虛擬地址指的是程序員看到的地址,實際物理地址是指硬盤上的地址空間。
二維數組在棧上分配時候,內存是連續的。在堆上分配注意連續性。
函數名就是函數的地址,函數指針知名返回類型和形參列表。函數地址傳遞給函數指針時候,必須返回類型和參數列表都要匹配上了纔可以。
帶參數的宏也是將代碼替換,類似於inline,但是參數傳遞時候,宏不是按值傳遞的,inline是按值傳遞傳參。
引用變量主要用於函數形參,聲明的引用變量和原變量具有相同的值和內存地址。
引用是先有原始變量,在把引用添上去,也就是聲明引用時候必須同時賦值。指針可以先有,然後再確定指向哪一個變量,可以先聲明後賦值。引用類似於打了死結的繩子,只能綁一個東西;而指針是打了活結的繩子,可以解開綁另一個東西。
函數參數傳遞: 值傳遞:跟實參完全無關
指針:解引用後就是實參
引用:本身就是實參
實參與const引用參數不匹配時候,c++將生成臨時變量:(只有const引用可以這麼搞)
1:實參類型正確,但不是左值
2:實參類型不正確,但可以轉換成正確的類型
爲什麼規定const引用才能這麼玩,如果非const,則可以通過引用修改實參,但是實參不匹配,這時就會創建個臨時變量,則引用實際改變的是臨時變量的值,並沒有改變實參。所以通過const禁止這種可能性,也就是實參跟引用變量不匹配時候只能訪問而不能改寫。
函數返回引用的原因:如果不是引用,函數會先把結果複製到一個臨時變量,然後在調用的時候,把臨時變量的值再複製給左值。如果是返回引用,則少了兩次拷貝。
函數返回引用:不能返回函數調用結束後不存在的內存單元(臨時變量)。避免的兩種方法:
1:返回引用參數
2:返回函數中新new的內存
函數參數的形式怎麼選擇:
內置類型,值傳遞
數組,只能使用指針
結構體,const 引用或者const 指針
類對象,const引用
函數帶不帶默認參數只體現在函數原型上,函數定義都是相同的。
函數重載的基礎是特徵標:
參數個數
是否爲const
類型
保證編譯器在函數調用時候可以匹配到原型。
編譯器內部怎麼識別重載函數呢?會根據形參類型和個數進行名稱修飾,通過特殊的規則添加冗餘信息,使其內部唯一。
函數模板:
模板並不創建任何函數,只是告訴編譯器如何定義函數。
將模板放到頭文件中,並在需要使用模板的文件中包含頭文件。
函數模板也可以重載。
函數模板爲什麼有特例化,主要是模板中的表達式用到的運算符在模板實例化時候的對象不支持那個運算符,比如T a+b, 有的對象不支持+。
如何匹配最佳函數?(重載,模板)
1.創建候選函數列表,以此創建可行函數列表,然後在列表中查找最佳的
decltype獲取不確定類型參數的類型,專用於模板函數。
針對decltype(expression) var; expression的情況分爲:
1.expression是沒有括號的標識符,則var和標識符類型相同
2.expression是函數調用,則var和函數返回值類型相同
3.expression是左值且帶有括號,則var是該類型的引用
4.除了上面,var的類型和expression類型相同
編譯命令:
g++ -std=c++11 -g syntex.cpp -o syntex
cc1plus: error: unrecognized command line option “-std=c++11”
g++ -std=c++0x -g syntex.cpp -o syntex
g++ --version 4.4.7 只能用-std=c++0x

函數返回const引用時候只能作爲右值, 而返回引用時候可以作爲左值
cout打印字符數組的地址
print, cout如果發現一個數組是字符數組,則會全部輸出,如果要輸出收地址,char buff[10]; cout<<(void*)buff<<endl;

數組作爲函數參數:
void fun(uint32_t num, capInfo workList[]) const;
void fun(uint32_t num, capInfo(&workList)[work_list_size]) cosnt; //推薦方式

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