C++ const限定符(一)

const限定符

有时候我们希望定义这样一种变量,它的值不能被改变,比如需要设置一个缓存区大小:

const int buffSize = 512;

这样就通过使用const限定符将这个大小设置为了常量,之后,任何为buffSize赋值的操作都将引发错误:

buffSize = 1024; //报错,试图向const对象写值

const对象一旦创建后就不能改变,因此必须初始化:

const int i = get_size(); //运行时初始化
const int j = 42;         //编译时初始化
const int k;             //未经初始化,报错

由于对象的类型决定了其上的操作,与非const对象能完成的操作相比,主要的限制就是不能执行改变其内容的操作。

在不改变const对象的操作中,还有一种操作是初始化操作,如果利用一个对象去初始化另一个对象,则它们是不是const对象都无所谓:

int i = 42;        //正确
const int ci = i;  //正确
int j = ci;        //正确


ci的常量特征仅仅在执行改变ci的操作时才会发挥作用。当用ci去初始化j时,根本无需在意ci是不是常量,拷贝一个对象的值并不会改变它,一旦拷贝完成,新的对象就和原来的对象没什么关系了。 

const的引用

可以把引用绑定到const对象上,称为对常量的引用。

const int ci = 1024;
const int &r1 = ci;  //正确,都是常量
r1= 42;             //报错,试图修改常量
int &r2 = ci;        //报错,试图让一个非常量引用去指向一个常量对象

为什么r2会报错呢?因为ci是常量,自然不允许为ci赋值,当然也不允许通过引用的方式去改变ci,因此r2的初始化是错误的。假设该初始化合法,那么就可以通过r2改变ci的值,显然不正确。

初始化和对const的引用

引用要求引用类型和对象的类型一致,这里存在两个例外

第一个例外:初始化常量引用时允许用任意表达式作为初始值,只要该表达式的结果能转换成引用的类型即可。尤其允许为一个常量引用绑定非常量的对象、字面值,甚至是个一般表达式。

看下面的例子:

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 &ri = dval;   //合法

这里ri引用了一个int型的数,对ri的操作应是整数运算,但dval却是一个double类型,因此为了让ri绑定上一个整数,编译器把上述代码变成了如下形式:

const int temp = dval;
const int &ri = temp;

ri绑定了一个临时量(临时创建的未命名的对象),如果ri不是常量,就允许对ri赋值,就会改变所引用对象的值,但此时绑定的是临时量,无法改变dval的值,归于非法,也就是说:

double dval = 3.14;
int &ri = dval;      //非法

常量引用仅限制了引用可参与的操作,对引用本身是否为常量未做限定。因此,对const的引用可能引用一个非const的对象。

指针和const

指向常量的指针不能用于改变其所指对象的值。想存放常量对象的地址,只能使用指向常量的指针。

const double pi = 3.14;
double *ptr = π           //错
const double *cptr = π    //对

指针类型同样要求类型一致,也存在两个例外:

第一个例外:允许令一个指向常量的指针指向一个非常量对象

double dval = 3.14;
const double *cptr = &dval; //合法

和常量引用一样,指向常量的指针也没有规定其所指的对象必须是一个常量,指向常量的指针仅仅要求不能通过该指针改变对象的值,而没有规定那个对象的值不能通过其他途径改变。

const指针

int a = 0;
int *const cur = &a;

const double pi = 3.14;
const double *const pip = π

指针是对象,所以可以把指针本身定义为常量。即常量指针。
必须被初始化,把*放在const之前说明指针是一个常量:隐含:不变的是指针本身而非指向的值

顶层const和底层const

顶层const表示指针本身是个常量
底层const表示指针所指向的对象是一个常量


更一般的:
顶层const可以表示任意的对象是常量,对任何数据类型都适用。
底层cosnt与指针和引用等符合类型的基本类型部分有关。
指针既可以是顶层const也可以是底层const

int i = 0;
int *const p1 = &i;             //不能改变p1的值,顶层const
const int ci = 42;              //不能改变ci的值,顶层const
const int *p2 = &ci;            //允许改变p2,底层const
const int *const p3 = p2;       //靠右的是顶层const,靠左的是底层const
const int &r = ci;              //用于声明引用的const都是底层const

执行对象的拷贝操作时,顶层const不受什么影响:

i = ci;
p2 = p3;     //p2和p3指向的对象类型相同,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上

 

 

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值