C++ const详解(一)

C++ const详解(一)

C和C++都有const这个关键字,虽然有相似,但是也有所不同。

const 在C++ 与C 的不同:

C中被const所修饰的叫做常变量,它具有变量属性,同时又具有常性,C编译器不能把const看成一个编译期间的常量,因为他在内存中有分配,在C中,const int a;是可以的,因为这只是声明一个变量,告诉编译器,我这里是声明,指明在别的地方有内存分配。但在C++中这样写是不正确的,因为const对象必须初始化,C++中const默认是内部链接1,C中默认是 外部链接2,为了起到和c语言一样的效果,C++需要将const修饰为extern 。即要在多个文件间共享const对象,必须在变量的定义之前加上extern。不过最好在变量的声明处也添加extern,作用是指明变量的定义在别处。

当在自己的文件中使用const的时候,C++不会为const常量分配空间,因为这是一种优化措施,没有必要浪费空间去存储一个常量,此时const int a=5 就相当于#define a 5,当在其他文件使用的时,需要分配内存,同样在程序内部引用的时候,也需要分配内存,因为这两者都是采用寻址的技术去使用的,不分配内存就没有地址。C++中定义常量的时候不再采用define,因为define只做简单的宏替换,并不提供类型检查。

const int i= get_size();//正确,运行时初始化
const int j= 42;//正确,编译时初始化
const int k;//错误,k是一个未经初始化的常量

const的引用

可以把引用绑定到const对象上,称为 对常量的引用,即不能被用作修改他所绑定的对象

const int ci= 1024;
const int &r1= ci;//正确,引用及其所引用的对象都是常量
r1= 42;//错误,r1是对常量的引用
int &r2= ci;//错误,试图让一个非常量引用指向一个常量对象

不能建立常量的普通引用,可以建立变量的常量引用
一般情况下,因为引用的类型必须与所引用对象的类型一致,但是初始化常量引用时,允许用任意表达式作为初始值,只要该表达式的值能够转化为引用的类型即可。

int i= 42;
const int &r1=i;//允许将const int&绑定到一个普通int对象上
const int &r2=42;//正确,r2是一个常量引用
const int &r3= r1*2;//正确,r3是一个常量引用
int &r4= r1*2;//错误,r4是一个普通的非常量引用

究其原因,其实是不同类型间建立引用时,编译器创建了一个临时量对象。
例如:

double dval =3.14;
const int &r1=dval;
//相当于
const int temp=dval;//由双精度浮点数生成一个临时的整型常量
const int &r1=temp;//让r1绑定这个临时量

当ri不是常量时
double dval=3.14;
int &r1=dval;
//相当于
int temp=dval;
int &r1=temp;
如果ri不是常量,就允许对ri赋值,即改变ri引用对象的值,注意此时绑定的是临时量而非dval,这样一来就没意义,所以
也就定义为 非法 ,即不同类型(可相互转化)间建立引用,只能是在const & 的前提下。

常量引用是对const的引用,而不是指引用本身是个常量虽然C++本身并不允许修改引用吗所绑定的对象,即所有的引用都算是常量。
同时,必须认识到,常量引用仅对引用可参与的操作做出了限定,对于引用的对象本身是不是一个常量未作限定,因为对象本身也可能是个
非常量,所以允许通过其他途径改变它的值。

int i=42;
int &r1=i;//引用ri绑定对象i
const int &r2=i;//r2也绑定i,但是不允许通过r2修改i的值
r1=0;//ri并非常量,i的值修改为0
r2=0;//错误,r2是一个常量引用

指针和const

const修饰指针,涉及到两个很重要的概念,顶层const和底层const
指针自身是一个对象,它的值为一个整数,表明指向对象的内存地址。因此指针的长度与所指向对象的类型无关,在32位系统下为4字节,64位系统下为8字节。进而指针本身是否是常量与所指向的对象是否是常量是两个问题。

顶层const: 表示指针本身是个常量
底层const:表示指针所指的对象是一个常量
一个指针可以既是顶层const,又是底层const.

int a = 1;
int b = 2;
const int* p1 = &a;
int* const p2 = &a;

根据从内到外,从右向左的原则来解读,p1是一个指针,指向int型对象,该对象是一个常量,因此为底层const
p2是个常量,同时是个指针,指向一个int型对象,因此为顶层const
一个指针,可以是指向常量的常量指针,并不冲突, 同时,和常量引用一样,指向常量的指针仅要求不能通过该指针改变对象的值,而没有规定那个对象的值不能通过其他方式改变。即指向常量指针可以指向非常量对象。

一般地,顶层const可以表示任意的对象是常量

当执行拷贝操作时,顶层const与底层const有很大区别

int errNumb=0;
int *const curErr=&errNumb;//curErr将一直指向errNumb
const double pi=3.14159;
const double *const pip= π//pip是一个指向常量对象的常量指针。
*pip=2.72;//错误,pip是一个指向常量的指针
const int ci=42;//一般的来说,ci是一个顶层const
const int *p2=&ci;//允许改变p2的值,这是一个底层const
const int *const p3=p2;//靠右的是顶层const,靠左的是底层const    p3是一个指向常量的常量指针,既是顶层又是底层
const int &r=ci;//只有对const的引用
int i=ci;//ci是顶层const,不会影响拷贝操作。
p2=p3;//p2和p3都是底层const,p3的顶层const部分不会影响

//从中看出,拷贝的对象是否是常量没关系,即顶层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资格,或者两个对象的数据类型必须能够相互转换,一般来说,非常量可转化为常量,反之不行

参考文章


  1. 内连接:编译器只对正被编译的文件创建存储空间,别的文件可以使用相同的表示符或全局变量.C/C++中内连接使用static关键字指定. ↩︎

  2. 外连接:所有被编译过的文件创建一片单独存储空间,一旦空间被创建,连接器必须解决对这片存储空间的引用,全局变量和函数使用外部链接。通过extern关键字声明,可以从其他文件访问相应的变量和函数。 ↩︎

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值