典型的函式定義包括:返回型別、函式名、由0個或多個形參組成的列表以及函式體。
形參初始化的機理和變數初始化一樣。
有兩種方式:引用傳遞和值傳遞
當形參是非引用型別時,形參初始化和變數初始化一樣,將實參的值拷貝給形參。
當執行指標拷貝操作時,拷貝的是指標的值,拷貝之後,兩個指標是不同的指標。但通過指標可以修改它所指的物件。
拷貝大的類型別物件或者容器物件比較低效,甚至有的類型別根本就不支援拷貝操作。當某種型別不支援拷貝操作時,函式只能通過引用形參訪問該型別的物件。
當用實參初始化const形參時會忽略頂層const。因此,當形參有頂層const時,傳給它常量物件或者非常量物件都是可以的。
void fun1(const int i)上述兩個函式不能算是過載,兩個函式是一樣的,程式會報錯,fun2重複定義了fun1.void fun2(int i)
可以使用非常量初始化乙個底層const物件,但是反過來不行。同時乙個普通的引用必須用同型別的物件初始化。
陣列有兩個重要的特性:
儘管不能以值傳遞的方式傳遞陣列,但是可以將形參寫成類似陣列的形式
void print(const int*);note:當函式不需要對陣列元素執行寫操作的時候,陣列形參應該是指向const的指標。只有當函式確實要改變元素值的時候,才把形參定義成指向非常量的指標。void print(const int);
void print(const int[10]);
以上三種形式的宣告等價
當陣列作為函式形參時,因此應該提供一些額外資訊來確定陣列的確切尺寸,管理陣列形參有三種常用的技術:
要求陣列本身包含乙個結束標記。例如c風格字串以空字元結尾。
傳遞指向陣列首元素和尾元素的指標。
void print(const int *beg,const int *end)形參可以是陣列的引用,此時,引用形參繫結到對應的實參上,也就是繫結到陣列上。;print(j, end(j)-begin(j));
void print(int (&arr)[10])error_msg();cout << endl;
}
error_msg(); //注意值的傳遞要放在花括號裡
省略符形參
省略符形參是為了便於c++程式訪問某些特殊的c**而設定的。通常,省略符形參不應用於其他目的。省略符形參只能出現在形參列表的最後乙個位置。
返回型別是void型別的函式
返回乙個值的方式和初始化乙個變數或形參的方式完全一樣:返回的值用於初始化呼叫點的乙個臨時量,該臨時量就是函式呼叫的結果。
auto sz=getstring().size(); //getstring返回的string物件再呼叫size函式呼叫乙個返回引用的函式得到左值,其他返回型別得到右值。
函式可以返回花括號包圍的值的列表。
vectorprocess()如果乙個函式呼叫了它自身,不管這種呼叫是直接還是間接的,都稱該函式為遞迴函式。;}
int factorial(int val)因為陣列不能被拷貝,所以函式不能返回陣列。不過,函式可以返回陣列的指標或引用。求1x2x3x4......
最直接的方法是使用型別別名
typedef int arrt[10];using arrt=int[10];
int arr[10]; //arr是乙個含有10個整數的陣列如果要定義乙個返回陣列指標的函式,則陣列的維度必須跟在函式名字之後,並且函式的形參列表應該先於陣列的維度。int *p1[10]; //p1是乙個含有10個整型指標的陣列
int (*p2)[10]=&arr; //p2是乙個指標,其指向乙個有10個整數的陣列
int (*func(int a,int b))[10];此函式返回的是乙個指向有10個整數陣列的指標。
任何函式的定義都能使用尾置返回,但是這種形式對於返回型別比較複雜的函式最有效,比如返回型別是陣列的指標或引用。
尾置返回型別跟在形參列表後面並以乙個->符號開頭。為了表示函式真正的返回型別跟在形參列表之後,我們在本應該出現返回型別的地方放置乙個auto。
auto func(int i)->int (*)[10];如果同一作用域內的幾個函式名字相同但形參列表不同,稱為函式過載。注意必須是形參列表不同,僅僅只是返回型別不同不可以稱為過載。
頂層const不影響傳入函式的物件。乙個擁有頂層const的形參無法和另乙個沒有頂層const的形參區分開來。
int f1(int i);但底層const不同,可以構成過載int f1(const int i); //不構成過載,重複宣告了f1
int f2(int *i);
int f2(int *const i); //不構成過載,重複宣告了f2
int f1(int &i);note:最好只過載那些確實非常相似的操作。int f1(const int &i); //過載,新函式
int f2(int *i);
int f2(const int *i); //過載,新函式
const_cast在過載函式的情景中最有用。
const string &shorterstring(const string &s1, const string &s2)如果在內層作用域中宣告名字,它將隱藏外層作用域中宣告的同名實體。string &shorterstring(string &s1, string &s2)
void func()預設實參、內聯函式和constexpr函式。int main()
一旦某個形參被賦予了預設值,它後面的所有形參都必須有預設值。
string screen(int i=10, int a=1, stirng s=" ");在呼叫函式的時候省略該實參就可以。
在給定的作用域中乙個形參只能被賦予一次預設實參。
區域性變數不能作為預設實參。除此之外,只要表示式的型別能轉換成形參所需的型別,該表示式就能作為預設實參。
呼叫函式一般比求等價表示式的值要慢一些。
在函式的返回型別前面加上關鍵字inline。
一般來說,內聯機制用於優化規模較小、流程直接、頻繁呼叫的函式。
constexpr函式是指能用於常量表示式的函式。
定義constexpr函式要遵循:函式的返回型別及所有形參的型別都得是字面值型別,而且函式體中必須有且只有一條return語句。
constexpr int new_sz()為了能在編譯過程中隨時展開,constexpr函式被隱式地指定為內聯函式。constexpr int foo=new_sz(); //foo是乙個常量表示式
note:constexpr函式不一定返回常量表示式。
和其他函式不一樣,內聯函式和constexpr函式可以在程式中多次定義。不過,對於某個給定的內聯函式或者constexpr函式來說,它的多個定義必須完全一致。因此,內聯函式和constexpr函式通常定義在標頭檔案中。
兩項預處理功能:assert和ndebug
assert巨集常用於檢查「不能發生」的條件。
assert(expr);如果expr為假,assert輸出資訊並終止程式執行,如果為真,assert什麼也不做。
assert的行為依賴於乙個名為ndebug的預處理變數的狀態。如果定義了ndebug,則assert什麼也不做,預設情況下沒有定義ndebug。
可以使用#define語句定義ndebug,從而關閉除錯狀態。
函式指標指向的是函式而非物件。和其他指標一樣,函式指標指向某種特定型別。函式的型別由它的返回型別和形參型別共同決定,與函式名無關。
int func(int a, string s);該函式的型別是int(int , string).要想宣告乙個可以指向該函式的指標,只需要用指標替換函式名即可。
int (*p)(int ,string ) //未初始化note:*p的括號必須加上
當把函式名作為乙個值使用時,該函式自動地轉換成指標。
int (*p)(int ,string )=func;可以使用函式指標直接呼叫該函式,而不需要解引用該指標。
指向不同函式型別的指標之間不存在相互轉換,可以給函式指標賦值nullptr和0,表示指標沒指向任何乙個函式。
如果定義了指向過載函式的指標,編譯器通過指標型別決定選用哪個函式,指標型別必須與過載函式中的某乙個精確匹配。
和陣列類似,雖然不能定義函式型別的形參,但是形參可以是指向函式的指標。可以直接把函式作為實參使用,此時它會自動轉換成指標。
注意將decltype用於函式名時,返回的是函式型別,而非指標型別,如果要表示函式指標,需要自己加上*。
C 系統學習之四 陣列
與vector的異同 陣列中元素的個數也屬於陣列型別的一部分,編譯的時候維度應該是已知的,也就是說,維度必須是乙個常量表示式。預設情況下,陣列的元素被預設初始化。note 可以對陣列元素進行列表初始化,此時允許忽略陣列的維度。當指定了維度,則維度應比列表初始值的數量多,當維度比初始化列表的數量大時,...
C 系統學習 陣列
與vector的異同相同 都是存放型別相同物件的容器不同 陣列的大小確定不變,不能隨意向陣列中增加元素 1 定義和初始化內建陣列 陣列中元素的個數也屬於陣列型別的一部分,編譯的時候維度應該是已知的,也就是說,維度必須是乙個常量表示式。預設情況下,陣列的元素被預設初始化。note 定義陣列的時候必須制...
linux系統學習之管道
首先理解管道其實是乙個二進位制位元組流,它是核心為維持兩個或多個程序互相通訊的一種手段 一種ipc 如下圖所示 include include include include include define buf siz 10 int main int argc,char argv write 1,...