IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C++知识整理系列(二)令人头疼的const -> 正文阅读

[C++知识库]C++知识整理系列(二)令人头疼的const

  • const修饰常量,这是总所周知的事情。
  • 但是,你可能会遇到以下头疼的问题:const int *是指针常量,int * const是常量指针,那么int const * 和 const int const *呢?
  • 本篇文章将深入分析const。

一、const基础概念

  • const限定符可以修饰变量、类等,限定它们不允许被改变
  • const是一个C语言的关键字,它限定一个变量不允许被改变。使用const在一定程度上可以提高程序的安全性和可靠性。
  • const 推出的初始目的,正是为了取代预编译指令,消除它的缺点,同时继承它的优点。

但是,在C++里,const的用法是在太多太复杂了:

二、const修饰变量

定义一个const修饰的常量:

const int bufSize = 256;

将变量bufSize定义为常量,之后不允许对其值进行修改,如:

bufSize = 64;//错误,视图向const对象写值

因为const对象一旦创建后其值就不能改变,所以const对象需要初始化时赋值:

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

三、const操作

限制:只能在const类型的对象上执行不改变其内容的操作。

(1)例如,const int可以和int一样,参与算术运算,也能被转换成一个布尔值。

const int x = 10;
int y;
y = 10 + x;//const类型的x参与算数运算

(2)用const初始化另一个对象

int i = 42;
const int t = i;		//正确:i的值被拷贝给t
int j = t;				//正确:t的值被拷贝给j

四、const对象的作用域

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

例如,const int size = 128;,编译器在编译过程中把用到size变量的地方,都用128替换。ps:注意区别于宏定义,宏定义虽然也是直接的文本替换,但是宏定义是在预处理阶段。

为什么const对象仅在单个文件内生效?

  • 为了实现上述的替换,编译器必须知道变量的初始值。如果程序包含多个文件,则每个用了const对象的文件都必须能访问到它的初始值才行。要做到这一点,就必须在每一个用到变量的文件中都有对它的定义。

  • 为了支持这一用法,同时避免对同一变量的重复定义,默认情况下,const对象被设定为仅在文件内有效。

  • 如果多个文件出现了同名的const变量,其实等于与在不同文件分别定义了独立的变量。

如何实现多文件共用?

有一种情况,const变量初始值不是一个常量表达式,但是又有必要在文件间共享。我们希望在一个文件定义const,而在其他多个文件声明并使用它。

解决办法:对于const变量,不管是声明还是定义都添加extern关键字:

//file.c文件
extern const int size = get_size();
//file.h文件
extern const int size;

在file.c文件定义并初始化了size。在file.h文件声明了size,表示size在外部定义。

五、const的引用

可以把引用绑定到const对象上,称之为:对常量的引用(reference to const)。

同样的,因为const对象是不能修改的,而对引用实际操作的也是这个对象,所以对常量的引用不能被用作修改它所绑定的对象。

const int size = 1024;
const int &r1 = size;		//正确:引用及其对应的对象都是常量
r1 = 512;					//错误:r1是对常量的引用,同样不可修改
int &r2 = size;				//错误:试图让一个非常量引用指向一个常量引用

常量引用是不允许修改的,假设int &r2 = size是合法的,那么就可以通过r2修改它引用的值,与常量引用不允许修改冲突,所以显然是不正确的。

引用的类型必须与其所引用对象的类型一致,但是有两个例外:

(1)初始化常量引用时允许用任意表达式作为初始值

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

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

要想理解这种例外情况的原因,看下面的例子:

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

这里ri引用了一个int型的数,但是对ri的操作应该是整数运算,而dval却是一个双精度浮点数而非整数。因此为了确保ri绑定一个整数,编译器把上述代码变成如下形式:

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

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

常量引用仅对引用可参与的操作做出了限定,对于引用的对象本身是不是一个变量未作限定。因为对象也可能是个非常量,所以允许通过其他途径改变它的值:

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

r1的值允许修改,而r2的值不允许修改,所以可以通过修改r1的值间接做到修改r2的值。

六、const和指针

指向常量的指针(指针常量)

与引用一样,也可以令指针指向常量或非常量。类似于常量引用,指向常量的指针(pointer to const)不能用于改变其所指对象的值。要想存放常量对象的地址,只能使用指向常量的指针

const double pi = 3.14;			//pi是个常量,它的值不能改变
double *ptr = π				//错误:ptr是一个普通指针,不能指向常量的地址
const double *cptr = π		//正确:cptr可以指向一个双精度常量
*cptr = 42;						//错误:不能给*cptr赋值

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

double dval = 3.14;
const double *ptr = dval;

所谓指向常量的指针,只是该指针不能修改对象的值罢了,没有规定该对象的值不能通过其他途径改变。

试试这样想:所谓指向常量的指针或引用,不过是指针或引用"自以为是"罢了,它们觉得自己指向了常量,所以自觉地不去改变所指对象的值。

常量指针

  • 指针是对象而引用不是,所以可以把指针定为常量。
  • 常量指针必须初始化,而一旦初始化,指针常量的值,也就是存放在指针中的地址就不能再改变了。
  • 定义常量指针,将*放在const关键字之前,说明指针是一个常量。而不变的是指针本身的值而非指向的那个值。也就是说,指着不能修改其指向,但是指向的值可以修改。

(1)如下,离cur最近的符号化是const,意味着cur本身是一个常量对象。const左边是int *,所以cur是常量指针。

int k = 1;
int *const cur = &k;				//cur将一直指向k

const double pi = 3.14159;
const double *const pip = π		//pip是一个指向常量对象的常量指针

(2)常量指针指向的是一般的非常量整数,所以修改常量指针指向的地址的值,即可以通过cur修改k的值。

*cur = 20;

顶层const

顶层const:表示指针本身是个常量——常量指针。

底层cosnt:指针所指的对象是一个常量——指向常量的指针。

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

当执行对象的拷贝操作时,常量是顶层const还是底层const区别明显:

  • 顶层const不受影响。

    i = ci;				//正确:拷贝ci的值,ci是一个顶层const,对此操作无影响
    p2 = p3;			//正确:p2和p3指向的对象类型相同,p3顶层const的部分不影响
    
  • 底层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和指针,const、变量类型、*的组合千千万万,关键在于:const默认作用于其左边的东西,左边无东西则作用于右边的东西

(1)指向常量的指针(指针常量)——指针指向的对象是常量,指针的指向可以修改,但是指针指向的地址的内容不可修改。

const int*int const*

按照规则,const优先作用于右边,否则作用左边。所以const int*中const修饰int,表示指针指向的int是常量。同理,int const*,const优先作用于右边,const修改时int。

(2)常量指针——指针本身是常量,所以指针所指向的地址不可变,但是指针指向地址的内容可以修改。

int *const

const优先作用左边 ,const修饰*,指针本身是常量。

(3)指向常量的常量指针——指针指向的地址不能变,指针指向的地址的内容不可变。

const int *constint const *const

const int *const

  • 左边的const左边无东西,作用于右边,左边的const作用于int。
  • 右边的const优先作用左边,右边的const作用于*

int const *const

  • 左边的const优先作用于左边,左边的const作用于int。
  • 右边的const优先作用于左边,右边的cosnt作用于*

可以发现,这两个都是同一个东西。

总之,记住const优先作用于左边,否则作用于右边。

参考



码字不易,觉得不错的小伙伴可以一键三连支持一下~
在这里插入图片描述

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-07-16 11:05:17  更:2021-07-16 11:05:21 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/5 16:22:36-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码