1.const字符定义
const字符是为了限定变量的值不允许被改变,也就是常量。防止程序不小心改变了这个值。当该变量初始化之后,任何试图对它进行赋值的行为都将引发错误。
const int a = 5;
a = 9; //限定了a为常量, 此处更改a的值将会报错。
2.初始化
因为const对象一旦创建后其值就不能改变,所以const对象必须初始化。而初始化的值是可以任意复杂的表达式的:
const int i = get_size(); //设定get_size函数会返回一个int型变量
const int j =42;
const int k; //未初始化,会引起错误/
当使用一个对象去初始化一个const对象时,并不需要这个对象是const类型的,因为它只是完成拷贝,拷贝一个对象的值并不会改变它,一旦拷贝完成,新的对象就和原来的对象没有关系。
3.作用域
const对象仅在文件内有效,当多个文件中出现了一个同名的const变量,其实他们之间是没有任何关系的。
某些时候,需要一个const变量需要在别的文件中共享,也就是只在一个文件中声明,在其它文件中也能使用。解决的办法是:对于const变量不管是声明还是定义都添加extern关键字,这样就只需要定义一次就可以了。例如:(实际测试中出现了指代不明的错误,而C++primer书中说可以实现,以下代码是手抄primer书中的列子)
//在文件file_1.cc中定义并初始化了一个const
extern const int buf_Size = fcn();
//在文件file_1.h中定义了一个同样一个const
extern const int buf_Size; //这与file1_1.cc中的buf_Size是同一个
4.const的引用和指针
可以把字符绑定到const对象上,就像绑定到普通常量一样,称之为对常量的引用。与普通引用不同的是,对常量的引用不能被用作修改它所绑定的对象:
int a = 5;
const int &b = a;
a = 8; //因为a 不是const 可以直接改变a的值
//b = 7; //不可以通过引用b来改变a的值,该位置报错
同样的,可以把const绑定到指针上,叫做指向常量的指针,它也不能用于改变其所指对象的值
#include<stdlib.h>
#include<string>
#include<iostream>
using namespace std;
int main() {
int a = 5;
const int &b = a;
a = 8;
//b = 7; //错误,不可以通过引用b来改变a的值
cout << b << endl;
const int *c = &a;
a = 10; //可以直接改变 a 的值
//*c = 15; 错误,不可以通过指针c来改变a的值
cout << b << endl;
system("pause");
}
自己总结了一下,const修饰的任意对象,无论是默认数据类型、对象、指针还是引用,都不能直接通过const修饰的对象间接的来改变,却可以直接修改它指向本身。
5.顶层const和底层const
顶层和底层const是在引用和指针中才有区分。顶层也就是引用和指针本身,底层是应用的地址对象和指针指向的对象。例如上面的例子,b和c就是顶层的const,a是底层。注意,a没有用const修饰,也就是它并不是底层const,所以还是可以修改的。当a定义为const int a时,a就是底层const。特殊一点的是,指针是可以指向对象的,所以指针既可以当顶层,也可以当底层。比较容易搞混的是定义的指针是顶层const还是底层const。
int a =5;
const int *b = &a; // 不可以通过*b改变a的值
int *const c = &a; // 指 c 指针指向的地址为常量,也就是不能改变c的指向地址
在上面的定义中,b 和c 都是指针,但是他们的意义是不同的,const int *b 指的是b的指向a为常量,注意,它所指向的常量a是指针自认为的,实际上是否是常量无所谓,也就是禁止通过指针b来改变a的值(b固执的认为我指向的对象就是常量,你让我改,当然是不能的),而int *const c的定义是指针c里面存放的地址为常量,也就是指向为常量,不可更改(不能改变c的地址)。例子:
#include<stdlib.h>
#include<string>
#include<iostream>
using namespace std;
int main() {
int a = 5;
int aa = 10;
const int *b = &a;
a = 99;
//*b = 77; 无法用b指针改变它指向内容的值
b = &aa;
cout << *b <<"--------------------------------"<< endl;
int *const c = &a;
*c = 88;
a = 8;
//c = &aa; 无法改变c指向的地址
cout << *c <<"------------------------------------------------"<< endl;
system("pause");
}
由上面的例子可以看出,所有const修饰的指针也仅仅影响到了指针本身的操作,而对a和aa的操作没有影响。
6.const做函数参数的修饰符
const是可以修饰函数中传递的参数的,这个方式一般用在引用传递和指针传递,因为普通的值传递对const的修饰没有意义。这种方式是为了防止在程序中修改原来的值,并且不用拷贝传递过来的对象,减小了开销。
#include<stdlib.h>
#include<iostream>
using namespace std;
void changeNum(const int &a);
void changeNum1(int &a);
void changeNum2(const int *a);
void changeNum3(int *a);
void changeNum4(int *const a);
int change = 123;
int main() {
int v = 9;
int vv = 99;
int vvv = 999;
int vvvv = 9999;
int vvvvv = 99999;
changeNum(v);
changeNum1(vv);
cout << "vv:" << vv << endl;
changeNum2(&vvv);
cout << "vvv:" << vvv << endl;
changeNum3(&vvvv);
cout << "vvvv:" << vvvv << endl;
system("pause");
}
void changeNum(const int &a) {
//a = 5; a不可被改变
int c = a;
cout <<"c:"<< c << "--------------------" << endl;
}
void changeNum1(int &a) {
a = 10;
}
void changeNum2(const int *a) {
//*a = 555; 不可以被改变a指向的值
int x = *a; //可以读取拷贝。
a = &change; //可以改变。 但是不会改变传递过来的vvv的值,相当于在这个函数中创建了一个零时的指针,指向了change,与vvv无关。
cout << "x:" << x << "-----------------------" << endl;
}
void changeNum3(int *a) {
*a = 1000;
}
void changeNum4(int *const a) {
*a = 7;
//a = &change; 不可以被修改
}
结果: