一、含义
1、顶层const表示指针本身是个常量,而用名词底层const表示指针所指的对象是一个常量;
2、更一般的说法,顶层const可以表示任意的对象是常量,这一点对任何数据类型都适用,如算数类型(整型和浮点型)、类,指针等。而底层const则与指针和引用等复合类型的基本类型部分有关。
int i = 0;
int *const p1 = &i; //顶层const,p1的值不能改变
const int ci = 42; //顶层const,ci的值不能改变
const int *p2 = &ci; //底层const,p2的值可以改变
const int *const p3 = p2; //靠右的const是顶层const,靠左的是底层const
const int &r = ci; //用于声明引用的const都是底层const
二、拷贝操作
1、当执行对象的拷贝操作时,顶层const几乎不受影响:
i = ci; //正确,拷贝ci的值,ci是一个顶层const,对此操作无影响
p2 = p3; //正确,p2和p3指向的对象类型相同,p3顶层const的部分不影响
2、当执行对象的拷贝操作时,拷入和拷出的对象必须具有相同的const资格,或者两个对象的数据类型必须能够转换。一般而言,非常量可以转换成常量,反之则不行。
int *p = p3; //错误,p3包含底层const,而p没有
p2 = p3; //正确,p2和p3都是底层const
p2 = &i; //正确,int*能转换成const int *
int &r = ci; //错误,普通的int&不能绑定到int常量上
const int &r2 = i; //正确,const int&可以绑定到一个普通int上
三、关于const的存储空间
参考http://www.cnblogs.com/yanqi0124/p/3795019.html中的大神写的内容。如下是我自己的测试代码。
“`
//测试
int main()
{
//第一种情况,使用c++中的const_cast进行转换
const int a = 1; //若a是全局变量,则出错。
int *p = const_cast<int*>(&a);
*p = 2;
cout << "value a = " << a << endl;
cout << "value *p = " << *p << endl; //输出1 2
cout << "address a = " << &a << endl;
cout << "address p = " << p << endl;
/*
第二种情况,禁用编译器优化,去掉常量重叠
volatile const int a = 1;
int *p = const_cast<int*>(&a);
*p = 2;
cout << "value a = " << a << endl;
cout << "value *p = " << *p << endl; //输出2 2
cout << "address a = " << &a << endl;
cout << "address p = " << p << endl;
*/
//第三种情况,使用强制转换,将内存位置存储的值改变了
//int i = 10;
//const int gc = i;
//int *t = (int *)&gc;
//*t += 2;
//cout << *t << endl << gc << endl; //输出12 12
//第四种情况,编译时常量重叠
//const int i = 1;
//int *p = (int *)&i;
//*p = 2;
//cout << *p << endl << i << endl; //输出2 1
//第五种情况,使用volatile去除编译器优化,禁用常量重叠
//volatile const int i = 1;
//int *p = (int *)&i;
//*p = 2;
//cout << *p << endl << i << endl; //输出2 2
return 0;
}
volatile关键字的两大作用:
一:告诉compiler不能做任何优化;
二:表示用volatile定义的变量会在程序外被改变,每次都必须从内存中读取,而不能把他放在cache或寄存器中重复使用。