顶层const作用与对象本身
const int ci = 42;//不能改变ci,const是顶层的
int i = ci;//正确:当拷贝ci 时,忽略了它的顶层const(就是说顶层const所指对象可以拷贝但不可以改变)
//ci = 43;报错
int *const p = &i;//const是顶层的,不能给p赋值(此时const修饰的 int *,即p是地址别名)
//int *const p = 2;不能给p赋值
//所以
*p = 0;//可以用p去修改i的值
所以当形参有顶层const,传给它常量对象或者非常量对象都是可以的:
void func(const int i){
//i = 42;报错
//func能够读取i 但是不能向i写值
}
指针或引用形参与const
可以用非常量来初始化一个底层const对象,但是不能用一个底层const对象来初始化一个非常量,一个普通的引用必须用同类型的对象初始化
int i = 42;
const int* cp = &i;//正确:但是cp不能改变i(因为这是底层const,const修饰的指向i的地址的别名cp)
const int& r = i;//正确:但是r不能改变i(因为这是常量引用,只能初始化不能改变值)
const int& r2 = 42;//正确:这是一个常量引用
int* p = cp;//错误 p是int*类型,cp是const int* 类型
int& r3 = r;//错误 r3是 int&类型,r是const int& 类型
int& r4 = 10;//错误不能用字面值初始化一个非常量引用
在参数传递上是同样的规则
void reset(int& i){i = 0;};
int main{
int i = 0;
const int ci = i;
string::size_type ctr = 0;
reset(&i);//错误调用的是int*的reset函数
reset(&ci);//错误不能用指向const int 对象的指针初始化int*
reset(ci);//错误不能把普通引用绑定掉const对象ci上
reset(42);//错误不能把普通引引用绑定到字面值上
reset(ctr);//错误类型不匹配
}
C++允许用字面值初始化常量引用,但是不能用字面值初始化非常量引用
函数形参尽量用常量引用
把函数定义为普通引用形参,会导致函数修改了实参的值,使用普通引用会限制函数所能接收的实参类型
6.2.3节练习
练习6.16
把函数定义为普通引用形参,会导致函数修改了实参的值,使用普通引用会限制函数所能接收的实参类型
bool is_empty(const string& s) {
return s.empty();
}
练习6.17
#include<string>
#include <iostream>
#include<cctype>
using namespace std;
bool capital(const string& word) {//因为参数不需要更改所以用了const
for (auto a : word) {
return isupper(a);
}
}
string lowerCase(string word) {//不能使用const,因为参数需要修改
for (auto &i : word) {//此处用引用的方式才能完整的更改完字符串
if (isupper(i))
i = towlower(i);
}
return word;
}
int main()
{
cout << capital("hello") << endl;
cout << lowerCase("HELLO") << endl;
system("pause");
return 0;
}
练习6.18
(a):
bool compare(const matrix &m1, const matrix &m2);
(b):
vector<int>::iterator change_val(int, vector<int>::iterator);
练习6.19
(a) calc(23.4, 55.1); // 不合法, 函数只有一个形参,传入两个实参不合法
(b) count("abcda", 'a'); // 合法
(c) calc(66); // 合法
(d) sum(vec.begin(), vec.end(), 3.8); // 合法
练习6.20
参数不需要修改时用常量引用
如果参数原本时常量引用,将它改为普通引用会导致程序编译不通过,还有可能会改变函数的实现结果