const简介
有时我们希望定义一种变量,他的值不再被改变,比如一个变量来表示缓冲区的大小,不需要再改变,这时就可以使用关键字 const 来对变量的类型加以限定。
const int bufSize = 512; bufSize = 1024; // 报错 cout << bufSize << endl;
如上所示: 我们对int类型的变量添加了const限定符,表示bufSize这个变量的值不可修改,对于下面的bufSize = 1024就会报错。这也就是const限定符的作用。
且const一定要创建后就初始化,如下:
const int i = get_size();// 在运行时初始化 const int j = 42; // 在编译时初始化 const int k; // 报错
第一个语句因为在编译阶段get_size()的运行结果还没有计算,所以只能在运行时初始化,而第二个语句就可以在编译阶段初始化,最后一句因为没有直接初始化就会报错。
const文件共享
这里我们定义的const类型变量只是在同一个文件中有效的,如果有多个文件,定义了多个常量,那么这些文件就不是共享的、而是独立的,所以,如果我们希望const常量可以在多个文件中共享,那么我们可以在const之前加入 extern 关键词。
如在file1.cpp中定义了:
extern const int bufsize = fun();
如果我们希望在file2.cpp中使用同一个变量,我们可以定义如下:
extern const int bufsize;
如上所示,我们这样定义,就可以将这个bufsize在file1和file2文件中共享了。
const与引用
另外,const变量的引用赋值上也是有一些注意点的,如下:
const int a = 50; const int &r = a; r = 40; // 报错:不能给常量赋值 int &r2 = a; // 报错
如上所示,因为r是a的引用,并且是const类型的,所以不能再次修改,且const型的变量只能使用const型的引用来引用,否则就会报错。
const与指针
同样的,const常量也只能用const类型的指针指向,否则就会报错,如下:
const int a = 50; int *r = &a;
而指针一旦是const类型,那么不能通过访问指针的形式修改对象。
const int a = 50; const int *r = &a; *r = 40; // 报错:不能给常量赋值
注意:实际上上面的const int *r的const类型是为了匹配上面的const int a的类型,这时,这里的r的指向还是可以再发生改变的,如下:
const int a = 50; const int b = 30; const int *r = &a; r = &b; cout << *r; //30
可以看到,虽然开始r指针指向的是a,但是之后我们又让r指向了b,也可以成功的,但是,如果我们希望这个指针指向一个对象之后,就不再改变,应该怎么样呢? 如下:
const int a = 50; const int b = 30; const int *const r = &a; r = &b; // 报错:不能给常量赋值
如上所示,一旦我们定义了这个r是const类型的,那么这个指针的指向就是不能再改变的了。
即指针本身就是对象,区别在于是 指针是常量 还是 指针所指向的是个常量。
顶层const与底层const
根据指针本身是否是常量以及指针所指向的是不是一个常量就是两个独立的问题,所以,用名词顶层const(top-level const)表示指针本身是个常量,而用名词底层const(low-level const)表示指针所指的对象是一个常量。
并且更一般的来说,顶层const可以表示任意的对象是常量,而底层const一般是与指针或引用等复合类型相关的。
int i = 0; int *const p1 = &i; // 这是一个顶层const; const int ci = 42; // 这是一个顶层const; const int *p2 = &ci; // 这是一个底层const; const int *const p3 = p2; // 右边的时顶层const; 左右的是底层const; const int &r = ci; // 用于声明引用的const都是底层const;
对于指针来说,指针本身是const,则是顶层const,如果是他所指向的是一个const,则是底层const,所以,顶层const指的是自身,而底层const不是自身,顶层cosnt的优先级会更高一些。