c++学习笔记——const限定符

 本博客作为我学习的笔记播客,仅供参考,如果有误,欢迎纠正。

在学习c++的过程中,开始接触const关键字时,感觉很简单,就是表示常量,不能修改,对于普通变量来说,确实如此。但是当const与引用和指针结合之后,情况就变得很复杂了,本篇想从根本上来解释这个问题。所有内容都是参考《c++primer》。本篇播客是按照知识点来进行讲解。

1.const对象必须初始化:

初始值可以是任意复杂的表达式和字面值。但是类型必须支持转换。

const int i = get_size();//正确,使用函数返回值初始化
const int j = 42;
const int k;//错误,没有初始化。

2.利用一个对象初始化另一个对象,双方是不是const都可以,即对象双方是不是const的,无关紧要。《c++primer》p53

注意:这里指的是初始化。这里意思是不区分const。这里的只包含普通的变量情况,引用和指针对const还是有要求,即常量可以引用/指向非常量和常量(非常量可以隐式转为常量),非常量不能引用/指向常量。

int i = 42;
const int j = i;//正确,使用一个非常量初始化一个常量。
int z = j;//正确,使用一个常量初始化一个非常量。

const int* a = &i;
const int* b = &j;
int* c = &i;
int* d = &j;//错误,非常量不能指向常量。

 3.const对象在文件中的作用范围:

const 对象和static对象一样,被设定为仅在当前文件有效,即当多个文件出现了同名的const变量时,其等同于在不同文件中分别定义了独立的变量。

措施:对于const对象不管是声明还是定义都添加extern关键字,这样就可以只定义一次。其他文件也能使用了

//在1.cpp中定义一个const变量
extern const int i = 42;
//2.cpp
extern const int i;//这里的i与上面的i是同一个。

4.常量引用仅对引用可参与的操作做出限定,对于引用的对象本身是一个常量还是一个非常量未作限定。《c++primer》p56

注意:这里是指的是常量引用。

int i = 42;
const int &r1 = i;//正确,使用非常量进行初始化。
const int &r2 = 42;//正确,使用字面值初始化。
const int &r3 = r1;//正确,使用一个常量进行初始化。
int &r4 = r1;//错误,r4不是常量,r1是const,即不是对常量对象进行初始化,就需要考虑const属性,不能任意初始化。
int &r5 = i;//正确,非常量对象,使用非常量进行初始化。

r1 = 40;//错误,r1是常量引用,不能修改。
r5 = 30;//正确,r5是非常量引用,可以修改。

非常量对象不能引用常量对象,即不能用常量对象来初始化非常量对象的引用。 

 5.指向常量的指针(指针常量)与常量引用一样,并没有规定其所指向的对象必须是一个常量,只是规定不能通过该指针改变对象的值而已。(指向可以改,不能改指向的值)

int  p = 42;
const int pi = 3;
const int* p1 = &p;//正确,p1指向一个常量
const int* p2 = π//正确,p2指向非常量
*P1 = 4;//错误,不能修改

int dval = 3.14;
p2 = &dval;//正确,指向一个非常量

int* p3 = pi;//错误,非常量不能指向一个常量。

这里指针和引用是一样的,非常量的不能指向/引用常量的,常量的可以指向/引用非常量和常量。

6.常量指针:指针是对象和引用不是,既然是对象,那就可以给指针增加const属性,即常量指针。一旦初始化之后,常量指针的值(存放在指针中的那个地址地址)就不能更改。(不能改指向,但可以改指向的值)

int i = 3;
int* const p = &i;//p将一直指向i;
int a = 4;
p = &a;//错误,不能在指向a
i = 1;//但指向的变量可以更改。

const int j = 0;
int* const p1 = &j;//错误,错误显式const int*不能初始化int* const。
前面我们说说了常量对象初始化的时候,是不区分const的。但是这里的常量指针表示
的就是一个常量指针,即顶层指针不能使用底层指针初始化。

下面是我的理解:
p1表示一个常量指针,即不能改变指向,可以改变值,j是一个常量,我们不能更改,
这不是冲突了嘛。

而且不想改变指向的值,我们是使用指针常量来实现的。
const int* const p2 = &i;
const int* const p2 = &j;

常量指针和指针常量的区分,很不容易区分清楚,这里需要好好理解,什么时候可以更改指向,什么时候可以改指向对象的值。

7.顶层const和底层const

顶层const和底层const就是常量指针和指针常量,顶层const(常量指针)表示的是指针本身就是一个常量对象,而底层const(指针常量)表示的是指针指向的是一个常量。这两句话请好好理解。其实从形式上很好区分这两个,从变量的右往左读。const在*右边是顶层const,反之底层const。

int i = 0;
int* const p1 = &i;//顶层指针,也是常量指针,不能改变p1,但可以改变i
const int b = 1;
const int* p2 = &b;//底层指针,也是指针常量,可以改变p2
const int* const p3 = p2;//第一个const表示底层const,第二个const表示顶层const,p3和p2都不能改变。


注意因为引用并不是对象,因此引用并没有顶层和底层的说法。

《c++primer》p58有一句话,当执行拷贝操作时,顶层const和底层const区别明显,其中顶层const不受什么影响(原文)。

一般来说,非常量可以隐式转换为常量。

int i = 0;
const int j = 1;
int& a = i;
int& b = j;// 错误,非常量引用常量
int* c = &i;
int* d = &j;// 错误,非常量指向常量
const int& e = i;
const int& f = j;
const int* g = &i;
const int* h = &j;
int* const k = &i;
int* const l = &j;//错误,const int*不能初始化 int* const


//这段代码建议自己复制到自己的电脑上去,看看是否报错。
//前面两个报错是因为非常量应用常量。
//后面一个错误情况,用下面的代码分析

const int a = 10;
int b = a;
const int* const p = new int(10);
int* p1 = p;//错误,非常量指向常量
int* const p2 = p;//错误p2
const int* const p2 = p;//正确p2
const int* p3 = p;

//这里p1报错,是因为非常量指向常量,
const int* r = &b;//正确,常量可以应用非常量,因为非常量可以转换为常量,反之,不可以。
因为顶层const在拷贝时不受影响,即可以从形式上忽略,即变为int* p2 = p;就是第一个错误非常量指向常量。
这种情况给他加上const就行了,p3相对于错误的p2就是加上const,正确。我们补上p2省略的const,
就是正确的p2的情况。p3就是没有顶层const的情况,这种就不需要考虑const了。


以上就是我对顶层const和底层const的理解。不知道讲解清楚没有,如果有错,欢迎指出。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值