const限定符

发布时间 2023-05-16 23:37:04作者: C++杀我

2.4 初始化和const

  • const对象一旦创建后其值就不能再改变,所以const对象必须初始化,并且可以是任意复杂表达式。
  • 如果利用一个对象去初始化另一个对象,则它们是不是const都无关紧要,例如:
int i = 42;
const int ci = i;     //正确:i的值被赋给了ci
int j = ci;       //正确:ci的值被赋给了j

  为什么呢,因为ci的常量特征仅在执行改变ci的操作时才会发挥作用(不允许修改ci的值),注重的是过程,而与到底是谁,是哪种类型初始化ci没有关系。

  • 默认状态下,const对象仅在文件内有效

   解决办法是,对于const对象,不管是在文件中声明还是定义都要添加extern关键字。

//file.c 定义并初始化了一个常量,并且该常量能被其他文件访问
extern const int bufsize = fcn();
//file.h  头文件
extern const int bufsize;

2.4.1  const的引用:对常量的引用

与普通引用(引用类型必须与引用对象类型一致)不同,常量引用:

  • 在初始化常量引用时 ,允许用任意表达式作为初始值。
  • 允许为常量引用确定非非非非非非常量的对象,字面值,甚至是一般表达式。

两种经典错误:

(1)

const int ci = 1024;
const int &r1 = ci;

r1 = 42;               //错误,常量引用r1不允许修改常量   
int &r2 = ci;     //错误:ci是常量不允许修改,但是r2是普通引用,存在修改ci的风险

不能用非常量的引用指向一个常量!!!

(2)

double dval = 3.14;
const int &ri = dval; 

ri引用了一个int类型的数,其对象也应该是int类型的,但是dval却是一个浮点数。因此为了确保让ri能够绑定一个整数,编译器把上述代码变成了如下:

const int temp = dval;  //让浮点数生成一个临时的整型常量
const int &ri = temp;    //让ri绑定这个临时的常量

乍一看其实没啥毛病,但是仔细想想,我的初心就是想让ri绑定dval,让ri能够修改dval的值,但是从底层来看,ri其实绑定了temp,也就是说无论我怎么修改ri,dval的值都不会被修改。那这样就没有意义了,所以这个代码运行是没问题的,但其实是非法的。

对const的引用可能引用一个并非const的对象

  必须认识到,常量引用仅仅对引用可参与的操作做出了限定,对于引用的对象本身是不是常量并未做限定,例如:

int i = 42;
int &r1 = i;           //引用r1绑定i
const int &r2 = i;    //常量引用r2也绑定i,但是不允许修改i的值
r1 = 0;          //允许                
r2 = 0;          //不允许

代码中,不允许通过修改r2修改i的值,尽管如此,i的值仍然可以通过其他途径修改(r1,i)。

 

2.4.2 指针和const

这部分内容,请看上一篇博客(引用和指针的区别)。

2.4.3 顶层const

如前所述,指针本身是一个对象,但是它又可以指向另外一个对象。因此存在两个独立的问题:指针本身是不是常量;指针所指的对象是不是常量。

  • 顶层(top-level const):指针本身是一个常量
  • 底层(low-level const):指针所值的对象是一个常量

 2.4.4 constexpr和常量表达式

常量表达式(const expression)是指: 值不会改变并且在编译过程中就能得到计算结果的表达式。

 get_size()函数 -- 直到运行时才能获取到,所以也不是常量表达式