練習 6.11 編寫並驗證你自己的reset
函數,使其作用於引用類型的參數。
#include<iostream>
using namespace std;
void reset(int &a) {
a = 0;
}
int main()
{
int x = 10;
cout << "x: " << x << endl;
reset(x);
cout << "x: " << x << endl;
return 0;
}
練習 6.12 改寫6.2.1節練習中的程序,使其引用而非指針交換兩個整數的值。你覺得哪種方法更易於使用呢?爲什麼?
#include<iostream>
using namespace std;
void swap(int &a, int &b) {
int tmp = a;
a = b;
b = tmp;
return;
}
int main()
{
int a = 1, b = 2;
cout << "a: " << a << "\nb: " << b << endl;
swap(a, b);
cout << "a: " << a << "\nb: " << b << endl;
return 0;
}
顯然引用更好。
練習 6.13 假設 T 是某種類型的名字,說明以下兩個函數聲明的區別:一個是void f(T)
, 另一個是 void f(&T)
。
前者是傳值,不能通過形參改變實參。
後者是傳引用,可以通過形參改變實參。
ps:我覺得後面的那種寫法應該是 void f(T &)
,直接用樹上的寫法會編譯出錯。
練習 6.14 舉一個形參應該是引用類型的例子,再舉一個形參不能是引用類型的例子。
交換兩個變量的數值,形參需要用引用類型。
當不希望函數改變實參的值而函數中又會更改形參的值時,則形參不能用引用類型。
練習 6.15 說明find_char
函數中的三個形參爲什麼是現在的類型,特別說明爲什麼s是常量引用而occurs
是普通引用?爲什麼s
和occurs
是引用類型而c不是?如果令s是普通引用會發生什麼情況?如果令occurs
是常量引用會發生什麼情況?
- 使用傳值方式的話,字符串複製的開銷很大,所以傳入引用;因爲函數保證不會修改s的值,所以用const引用來加以限制。
- 因爲調用者是通過occurs來隱式地獲得c的出現次數的,所以需要函數在其操作中修改occurs來進行計數並返回給調用者。
- 因爲c通常情況下會傳入一個字面值,並且由於c僅僅是一個char類型,所以通過傳值方式調用更方便快捷。
- 在這個函數中不會發生特殊情況,但是如果不加const限制,則有可能會在函數中修改s變量。
- 會導致函數不能正常修改occurs,導致錯誤。
練習 6.16 下面的這個函數雖然合法,但是不算特別有用。指出它的侷限性並設法改善。
bool is_empty(string& s) { return s.empty(); }
侷限性在於常量字符串和字符串字面值無法作爲它的實參
可以改爲:
bool is_empty(const tring &s){return s.empty();}
練習 6.17 編寫一個函數,判斷string
對象中是否含有大寫字母。編寫另一個函數,把string
對象全部改寫成小寫形式。在這兩個函數中你使用的形參類型相同嗎?爲什麼?
#include<iostream>
#include<string>
#include<cctype>
using namespace std;
bool haveupper(const string &s) {
bool flag = false;
for (auto c : s) {
if (isupper(c)) {
flag = true;
break;
}
}
return flag;
}
void beclower(string &s) {
bool flag = false;
for (auto &c : s) {
c = tolower(c);
}
}
int main()
{
string a = "ABCDaaaa";
cout << a << endl;
cout << haveupper(a) << endl;
beclower(a);
cout << a << endl;
cout << haveupper(a) << endl;
return 0;
}
不同,因爲函數的需求不同,第一個函數只需要訪問字符串s即可,所以用const
引用類型,而第二個函數需要訪問並修改字符串s,所以用普通引用類型。
練習 6.18 爲下面的函數編寫函數聲明,從給定的名字中推測函數具備的功能。
- (a) 名爲
compare
的函數,返回布爾值,兩個參數都是 matrix 類的引用。 - (b) 名爲
change_val
的函數,返回vector
的迭代器,有兩個參數:一個是int
,另一個是vector
的迭代器。
bool compare(matrix &a, matrix &b);
vector<int>::iterator change_val(int x, vector<int>::iterator iter)
練習 6.19 假定有如下聲明,判斷哪個調用合法、哪個調用不合法。對於不合法的函數調用,說明原因。
double calc(double);
int count(const string &, char);
int sum(vector<int>::iterator, vector<int>::iterator, int);
vector<int> vec(10);
(a) calc(23.4, 55.1);
(b) count("abcda",'a');
(c) calc(66);
(d) sum(vec.begin(), vec.end(), 3.8);
(a)不合法,calc只有一個參數,調用時卻傳入了兩個值。
(b)合法
©合法
(d)合法
練習 6.20 引用形參什麼時候應該是常量引用?如果形參應該是常量引用,而我們將其設爲了普通引用,會發生什麼情況?
當只需要訪問實參的值,而不需要更改實參時,一個用常量引用。
可能會導致本應該合法的調用不合法。