const 可意为不变的、不能改变的、常量、只读
简单分为以上4种应用:
- const int(double,float ,bool…) 。
- const int&
- const int *,int *const p;
- constexpr(c11)和常量表达式
先分析几个例子吧:
在此之前我们先弄懂初始化和赋值的区别:初始化的含义是创建变量时赋予其一贯初始值,而赋值的含义是把对象的当前值擦除,而以一个新值替代
对于1:
int get()
{return 10;}
const int f=get(); //f=10;
const int x=10;//初始化一个不可变的整形变量
const int x//错误:k是一个未经初始化的常量
x=5;//错误,赋值左值必须可改变,(不然怎么把当前值擦除,又如何替代?)
int &c1=x //错误,常量只能常引用
对于2:
const int ci=1024;
const int &ri =ci//正确引用及其对应的对象都是常量
ri = 42//错误,r1 是对常量的引用不可变。
int &r2 =ci// 错误:非常量引用不能指向一个常量引用。
//另外 ,const 类型转变会产生零时量对象,如:
double dval=3.14;
const int &r1=dval;
/*==const int temp=dval;
const int &ri=temp; */
对于3:
我们可以这样分析归纳:
一种类型的初始化,(无括号)可以从右往左读,先读到什么就先是什么类型的。
- const int *p1 ,这里p1先和 * 结合即p1是指针变量,再和int 结合就是:指向整形对象的指针,再和const 结合便是 指向const(“不能改变”)整形对象的指针
- int cosnt p2,这里 p2先和cosnt 结合,则 p2是const(不能改变的),再和结合则是:const(不能改变(指向)的)指针,再和int 结合就是 p2是指向整形对象的 const(不能改变(指向)的)指针
const int a = 5;
int b = 10;
const int *p1 = &a; //正确,*p1和a都是const的值
//p1是底层const 表示指针所指的对象是一个“常量”
int *const p2 = &a;//错误,*p2没有被const ,不能指向const 整形
//p2是顶层const,表示指针本身是个常量
const int *p1 = &b;//正确,const *或&都是他们“一厢情愿”认为指向const
int *const p2 = &b;
*p1 = 10; //错误:*p1 是const
p1 = &b; //正确,p1不是const的 可以改变指向。
p2 = &b; // 错误,p2是const的 不可以改变指向
*p2 = 5; //正确,*p2不是const
感觉和中文挺像的,比如:
我有一个帅气的(int)朋友的不懂变通的(const)朋友。
我有一个不懂变通的(const)朋友的帅气的(int)朋友。
这样分析可以理解大多数一般情况。
const int*和 const
所谓指向常量的指针或引用,不过是指针或引用“一厢情愿”罢了,他们觉得自己指向了常量,所以不能去改变所指对象的值
因此 2 和3一般用来做函数形参用来输出或者参与一些运算(不改变原值比如 display(const int & a)用以只读输出。
对于4:
C++11新标准规定,允许将变量声明为constexpr类型以便由编译器来验证变量的值是否是一个常量表达式。声明为constexpr的变量一定是一个常量,而且必须用常量,但是constexpr函数不一定返回常量
表达式初始化:
传给constexpr函数常量表达式则返回常量表达式,否则返回非常量表达式
inline constexpr int new_sz()
{
return 42;
}
inline constexpr size_t scale(size_t cnt)
{
return new_sz() * cnt;
}
int main()
{
constexpr int foo = new_sz(); //正确,foo是一个常量表达式
int arr[scale(2)]; //传常量得常量,正确
const int i=2;
int j = 10;
//int a2[scale(j)]; //错误,scale(j)不是常量
cout << "sizeof of a2 is " << sizeof(arr) << endl; //42*2*4=336
return 0;
}
最后总结一下:const 写在谁前面,谁就是const的。
另外使用到typedef 时,不能直接把typedef 的原名 直接接到const后直译
typedef char *pstring;//pstring 是char* 的同义词
const pstring cstr = 0; //cstr 是指向char的常量指针
//因为pstring 首先是指针,然后再const, 便修饰的是指针。
//不能直译为 const char *cstr
const char *cstr2 = 0;
*cstr2 = 1;// 错误:cstr2是指向常量的指针,(*cstr2)(常量)不可修改
cstr2 = 0;//正确:cstr不是常量。
*cstr = 1;//正确:cstr(是常量)是一个指向char的常量指针,则(*cstr)(不是常量)可修改
cstr = 0;//则cstr的值不可修改
另外数组也可以被看成 * const 即不能改变指向的指针
数组的地址是不可改变的,解释了数组可被初始化而不能整体(首地址||头指针)赋值的原因。