关于const常量、const指针以及const引用

时间:2022-09-22 20:23:28

这篇博客从头到尾的讲一下关于const的一些问题,本人是编程小白,写的不好的地方还请指出。

1.const常量

与变量不同,有const修饰的量是常量,常量的值不可改变,在定义的时候必须初始化,使用未初始化的常量是错误的。以前还经常弄不清楚的问题就是常量和变量的赋值问题,例如如下代码:

int a=3;
const int b=a;
a是一个变量,而b是常量,能否用一个变量给常量赋值呢?答案是可以的,变量在这里只起到赋值的作用,而常量b也仅仅是用a的值来初始化,就相当于常量b用一个具体的数值来初始化一样。还有如下代码:
int a;
const int b=6;
a=b;
同样也是正确的,仅仅用b的值来给a赋值。

另外:const int a与int const a表达的意思相同。

2.const指针

首先讲解一下指针:指针是一个对象(与引用不同),也是复合类型的一种,指针用*运算符来修饰。指针有自己的空间地址,指针中存放的是所指对象的地址,不同类型的指针可以指向特定类型的对象,即指针的类型要与所指向的对象的类型一致。可通过指针改变所指向的对象的值。

int a;
int *p=&a;
*p=5;
cout<<a<<endl;

上例代码输出结果为5,即通过指针改变了对象a的值。

double f=3.124;
int *p=&f;
就会出现编译错误,因为对象与指针类型不匹配。

常量指针与指针常量:

常量指针:

const int *p;
int i=34;
int j=90;
p=&i;
 
p为常量指针。这里应该注意的是,虽然按照字面意思理解,p指向的对象是常量,即i应该是一个常量,而不是上述代码的变量,那么p指向变量i为什么对呢?其实,p“自以为是”的认为自己所指向的对象一定是常量,其实不然。常量指针既可以指向常量,也可以指向变量,常量指针的真正含义在于不能通过p来改变所指向对象的值,并不代表不能通过其他途径来改变对象的值。比如: 
const int *p;
int i=34;
int j=90;
p=&i;
int *r=&i;
*r=8;
指针p和r同时指向变量a,这里通过指针r改变了对象i的值,是正确的。如果再加一句:*p=9;则是错误的,因为常量指针不允许通过自身来修改对象的值.
const int *p;
int i=34;
p=&i;
int *r=&i;
*r=8;
*p=9;

常量指针指向的地址可以变,p指针先是指向i,最后又指向j:

const int *p;
int i=34;
int j=98;
p=&i;
p=&j;
指针常量
int i=89;
int * const p=&i;
指针p中存放的地址不可改变,即p只能初始化,不能改变所指向的对象,对象的值可以通过p来改变。如下代码就是错误的:
int i=89;
int * const p=&i;
int j=56;
p=&j;

3.const引用

引用:引用即别名,用“&”来修饰,这里的&并不是取地址符,而是代表复合类型--引用。引用必须初始化,可以通过引用改变对象的值。

int a;
int &b=a; 
cout<<"&a:"<<&a<<endl; 
cout<<"&b:"<<&b<<endl;
b=4;
cout<<"a:"<<a<<endl;
cout<<"b:"<<b<<endl;

 

b与a的输出地址相同,此时b就是a的一个别名,他们占用同一个内存空间,修改b的值,就相当于在修改a 的值。

刚开始接触引用的时候,c++ primer这本书上说,引用不是对象,只是对象的别名,所以引用不能像定义“指针的指针”那样来定义“引用的引用”,打个比方:我们都有一个大名,有的人有个小名,他们指的都是一个人,但是身份证上只能填写你的大名,而不能填写小名,引用就是这个道理。

引用一旦与对象绑定,中途不可改变对象:

int a;
int &b=a; 
cout<<"&a:"<<&a<<endl; 
cout<<"&b:"<<&b<<endl;
int i=5;
b=i;
cout<<"&b:"<<&b<<endl; 
cout<<"&i:"<<&i<<endl;
b的地址并没有改变,只是其中的值改变了而已。

引用只能绑定在对象上,不能与表达式的结果或字面值绑定在一起,如下就是错误的:

int  &ra=1024;

const引用:

const引用是指--指向const的引用,其实这样说也不恰当,和const指针一样,const引用可以与常量绑定,也可以与变量绑定,只是不能通过这个const引用来改变绑定对象的值,就如上所讲的const指针类似。

<span style="font-size:12px;">int a=10;
const int &ra=a;
a=5;//正确
ra=4;//错误,不能通过引用改变a的值</span>

非const引用不能与const对象绑定,因为常量a的值不可改变,但却可以通过非const引用来改变常量a的值,这样做是错误的,如下:

<span style="font-size:12px;">const int a=10;
int &ra=a;//错误,非const引用不能绑定到const对象</span>

引用的类型必须与所引用的对象类型一致,但是有例外情况:在初始化常量引用时可以用任意的表达式作为初始值,只要表达式的结果能转换成引用的类型。

int i=42;
const int &r1=i;//正确
const int &r2=42;//正确,r1是const引用
const int &r3=r1*2;//正确,r1是const引用
int &r4=32;        //错误,r4不是const引用
为什么会出现这样的情况呢?先来弄清楚const引用绑定到类型不匹配的对象类型上时发生了什么:

double d=3.1415;
const int &rd=d;

执行const int &rd=d时,发生了这种情况:const int temp=d;const int &rd=temp;所谓临时变量就是编译器需要一个空间暂存表达式的求值结果时临时创建的未命名的对象。而假如rd不是一个常量引用,在对rd赋值时,就会改变rd所绑定对象的值。但此时绑定的对象是一个临时的量,它没有名字,而不是绑定了d,既然rd绑定了d,肯定是想通过rd改变d的值,否则干嘛将d绑定到rd呢?但是此时非const修饰的rd改变不了d的值,那绑定也就无意义,所以编译器不允许这样做。