通過呼叫運算子(call operator)來執行函式。呼叫運算子的形式是一懟圓括號(),它作用於乙個表示式,該表示式是函式或者指向函式的指標;呼叫表示式的型別就是函式的返回型別。 int function() 是乙個呼叫表示式,是用呼叫運算子()作用於函式名function(實際上是指標),int型別為呼叫表示式的型別,也是函式的返回型別;
函式的三要素(返回型別,函式名,形參型別) 描述了函式的介面,說明了呼叫該函式所需的全部資訊。函式宣告也稱作函式原型;
使用引用來避免拷貝,當拷貝打的類型別物件或者容器物件時,由於拷貝比較低效甚至有的物件不支援拷貝構造,這是使用引用形參是比較明智的選擇;
當函式無需改變引用形參的值時,最好將其宣告為常量引用;
當用實參初始化形參是會忽略掉頂層const(形參的頂層const被忽略了),當形參有頂層const時,傳給他常量或者非常量物件都是可以的;
//下面兩句語句是等效的,因此不能視作函式過載
void fun(const int i) {} ;
void fun(int i) {};
練習6.17
bool hasupper(const string&str)
return false;
}void strtolower(string& str)
return;
}
陣列的兩個特殊性質:不允許拷貝陣列,使用時將轉化為指標;導致無法以之傳遞的形式使用陣列引數,但是可以把形參寫成類似陣列的形式,以下三種宣告方式等效:
void print(const *int);
void print(const int); //可以看出函式的意圖是作用乙個陣列
void print(const int[10]); //這裡的維度表示期望陣列有多少個元素,無論寫多少都是將第乙個元素的指標傳入
3種辦法管理指標型形參使其不越界:
// 1. 使用標記指定陣列長度,這裡c風格字串結尾標記是'\0'
void print(const char *p)
// 2. 使用標準庫規範, begin(), end()函式可以返回容器內容的第乙個元素的指標迭代器和最後乙個元素下一位的指標迭代器
void print(const int *beg, const int *end)
cout<
返回區域性物件的引用是錯誤的;同樣,返回區域性物件的指標也是錯誤的
呼叫運算子()的優先順序與點運算子.和箭頭運算子->一樣,同時滿足左結合律因此下面語句可以正常執行auto sz = shorterstring(s1,s2).size();
函式的返回型別決定函式呼叫是否為左值。呼叫乙個返回引用的函式得到左值,可以為其結果賦值(常量引用例外)
//這裡函式返回的是char型的引用,作為左值可以為其賦值
char &get_val(string &str, string::size_type ix)
int main()
合法,只要其型別符合返回值的型別;
宣告乙個返回陣列指標的函式有兩種方式,閱讀理解順序從內到外,從右到左
int (*func(int i))[10] ;//函式func有乙個引數i,返回乙個指標,指向有10個int型的陣列
auto func(int i) -> int(*)[10] ; //㞑置返回型別,顯式提示真正的返回型別
不允許兩個函式除了返回型別外其他所有的要素都相同;對於過載的函式來說,他們應該在形參數量或者形參型別上有所不同;
頂層const不影響傳入函式的物件。乙個擁有頂層const的形參無法和另乙個沒有頂層const的形參區分開來
int lookup(phone);
int lookup(const phone); //重複宣告
形參如果是某種型別的指標或者引用,則可以通過const區分函式過載,此時的const是底層的
record lookup(account&);
record lookup(const account&); //新函式,作用於常量引用
record lookup(account*); //新函式,作用於指向account的指標
record lookup(const account*); //新函式,作用於指向常量的指標
同名函式宣告置於區域性作用於內實現的是隱藏而不是過載,詳見210頁
一旦某個形參被賦予了預設值,那麼它後面所有的形參都必須有預設值;
多次宣告乙個函式是合法的,但是在給定的作用域中乙個形參只能被賦予一次預設實參;換句話說,函式的後續宣告只能為之前沒有預設值的形參新增預設實參,而且該形參右側的所有形參必須都有預設值;
區域性變數不能作為預設實參
typedef string::size_type sz;
sz wd = 80;
char def = ' ';
sz ht();
string screen(sz = ht(), sz = wd, char = def);
string window = screen(); //呼叫 screen(ht(), 80, ' ')
void f2() //函式區域性作用域
constexpr函式不一定返回常量表示式,當constexpr函式實參是常量表示式時其返回值為常量表示式,實參不是是返回的就不是常量表示式;內聯函式和constexpr函式可以多次定義,但是對於給定的內聯函式或者constexpr函式來說,它的多個定義必須完全一致,因此這兩個函式通常定義在標頭檔案中;
assert是預處理巨集,定義在標頭檔案中,它的名字由預處理器管理因此不需要提供using assert或者std::assert; 很多標頭檔案都包含了,因此即使你沒有直接包含cassert,它也有可能通過其他途徑包含在程式中;
ndebug預處理變數用於除錯時檢查,詳見216頁
函式匹配的過程分3步,第一步確定候選函式,即找到同名的過載函式;第二步確定可行函式,匹配實參數量型別和形參數量型別;第三步尋找最佳匹配,完美匹配引數數量和型別的優先順序最高,其次是可以型別轉換的引數;當無法找到完美匹配的函式時編譯器最終將因為呼叫具有二義性而拒絕請求;詳見218頁;
實參型別轉換排序等級 a,精準匹配, b通過const轉換實現的匹配, c通過型別提公升實現的匹配, d通過算術型別轉換或者指標轉換實現的匹配, e通過類型別轉換實現的匹配;從a到e優先順序依次降低;
當我們把函式名作為乙個值使用時,該函式自動地轉換成指標
pf = lengthcompare; //pf指向名為lengthcompare的函式
可以用指向函式的指標呼叫該函式,無需提前解引用指標
bool b1 = pf("hello","goodbye");bool b2 = (*pf)("hello","goodbye");
bool b3 = lengthcompare("hello","goodbye");
//以上三種呼叫等價
把函式直接作為實參使用,此時它會自動轉換成指標;直接使用函式指標閒的冗長繁瑣,因此可以使用型別別名(using操作)和decltype簡化寫函式指標的**
返回指向函式的指標,建議用㞑置返回型別的方式,顯示的宣告太複雜不容易看懂;
int(*f1(int))(int* int);
auto f1(int) -> int(*)(int*,int);
//以上兩種宣告方式等價,返回指向引數為(int*,int),返回值為int的函式指標
C Primer第五版筆記 關聯容器
一 型別 關聯容器支援高效的關鍵字查詢和訪問,標準庫中兩個主要的關聯容器是map和set。map中的元素是鍵值對關鍵字表示索引。set中每個元素只包含乙個關鍵字,set支援高效的關鍵字查詢。關聯容器根據三個特性可以分為8種 1 set還是map 2 關鍵字是否可以重複,允許重複的容器名字中都包含單詞...
C Primer第五版筆記 動態陣列
allocator類 為了讓new分配乙個物件陣列,需要在型別名後跟方括號,括號中是分配物件的數目,該數目必須是整型,但不必是常量 new t 分配的記憶體並不是得到乙個陣列,而是得到乙個陣列元素型別的指標,因此不能對動態陣列呼叫begin和end 與普通陣列不同的是,普通陣列不能定義長度為0的陣列...
C Primer第五版筆記 拷貝控制
拷貝賦值函式 析構函式 三 五法則 default和阻止拷貝 乙個類通過定義五種特殊的成員函式來控制其拷貝 賦值 移動以及銷毀操作 拷貝建構函式 拷貝賦值運算子 移動建構函式 移動賦值運算子和析構函式。這些操作都是拷貝控制操作。當實現自己的類的時候要想好在做這些操作時的規則,因為編譯器通常會自動生成...