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 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> C++Primer第2章(4)const限定符 -> 正文阅读

[JavaScript知识库]C++Primer第2章(4)const限定符

2.4 const限定符

? const对象一旦创建后其值就不能再改变,所以const对象必须初始化,初始值可以是任意复杂的表达式.

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

初始化和const

? 只能对const类型的对象执行不改变其内容的操作.在不改变const对象的操作中还有一种是初始化,如果利用一个对象去初始化另外一个对象,则它们是不是const都无关紧要.

int i = 42;
const int ci = i;	//正确:i的值背靠背给了ci
int j = ci;			//正确:ci的值被拷贝给了j

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

如果想在多个文件之间共享const对象,必须在变量的定义之前添加extern关键字

2.4.1 const的引用

? 可以把引用绑定到const对象上,就像绑定到其他对象上一样,我们称之为对常量的引用.对常量的引用不能被用作修改它所绑定的对象:

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

image-20211126191016993

初始化和对const的引用

  • 在初始化常量引用时允许用任意表达式作为初始值,只要该表达式的结果能转换成引用的类型即可.允许为一个常量引用绑定非常量的对象,字面值,甚至是一个一般表达式
int i = 42;
const int &r1 = i;
const int &r2 = 42;
const int &r3 = r1 * 2;
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 绑定了一个临时量对象。所谓临时量对象就是当编译器需要一个空间来暂存表达式的求值结果时临时创建的一个未命名的对象。C++程序员们常常把临时量对象简称为临时量。

对const的引用可能引用一个非const的对象

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

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

? r2绑定(非常量)整数i是合法的行为。然而,不允许通过r2修改i的值。尽管如此,i的值仍然允许通过其他途径修改,既可以直接给i赋值,也可以通过像r1一样绑定到i的其他引用来修改。

2.4.2 指针和const

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

const double pi = 3.14;
double *ptr = π   //错误:ptr是一个普通指针
const double *cptr = π//正确:cptr可以指向一个双精度常量
*cpte = 42;			//错误:不能给*cptr赋值
  • 允许令一个指向常量的指针指向一个非常量对象
double dval = 3.14; 
cptr = &dval;		//正确:但不能通过cptr改变dval的值

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

所谓指向常量的指针或引用,不过是指针或引用“自以为是”罢了,它们觉得自己指向了常量,所以自觉地不去改变所指对象的值.

const指针

? 常量指针必须初始化,而且一旦初始化完成,则它的值(也就是存放在指针中的那个地址)就不能再改变了.把*放在const关键字之前用以说明指针是一个常量,这样的书写形式隐含着一层意味,即不变的是指针本身的值而非指向的那个值:

int errNumb = 0;
int *const curErr = &errNumb;//curErr将一直指向errNumb
const double pi = 3.14159;
const double *const pip = π//pip是一个指向常量对象的常量指针

? 指针本身是一个常量并不意味着不能通过指针修改其所指对象的值,能否这样做依赖于所指对象的类型.

image-20211126203851200

2.4.3 顶层const

? 如前所述,指针本身是一个对象,它又可以指向另外一个对象.因此,指针本身是不是常量以及指针所指的是不是一个常量就是两个相互独立的问题.用名词顶层const表示指针本身是个常量,而用名词底层const表示指针所指的对象是一个常量.

? 更一般的,顶层const可以表示任意的对象是常量,这一点对任何数据类型都适用,如算术类型、类、指针等.底层const则与指针和引用等复合类型的基本类型部分有关.比较特殊的是,指针类型既可以是顶层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
const int &r = ci; //用于声明引用的都是底层const

? 当执行对象的拷贝操作时,顶层const不受影响.

i = ci; //正确,拷贝ci的值,ci是一个顶层const,对此操作无影响
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上

? p3既是顶层const也是底层const,拷贝p3时可以不在乎它是一个顶层const,但是必须清楚它指向的对象得是一个常量。因此,不能用p3去初始化 p,因为p 指向的是一个普通的(非常量)整数。另一方面,p3的值可以赋给p2,是因为这两个指针都是底层const,尽管p3同时也是一个常量指针(顶层const),仅就这次赋值而言不会有什么影响。

  • 执行对象拷贝时有限制,常量的底层const不能赋值给非常量的底层const。

    int num_c = 3;
    const int *p_c = &num_c;  //p_c为底层const的指针
    //int *p_d = p_c;  //错误,不能将底层const指针赋值给非底层const指针
    const int *p_d = p_c; //正确,可以将底层const指针复制给底层const指针
    
  • 使用命名的强制类型转换函数const_cast时,需要能够分辨底层const和顶层const,因为const_cast只能改变运算对象的底层const。

    int num_e = 4;
    const int *p_e = &num_e;
    //*p_e = 5;  //错误,不能改变底层const指针指向的内容
    int *p_f = const_cast<int *>(p_e);  //正确,const_cast可以改变运算对象的底层const。但是使用时一定要知道num_e不是const的类型。
    *p_f = 5;  //正确,非顶层const指针可以改变指向的内容
    cout << num_e;  //输出5
    

2.4.4 constexpr和常量表达式

? 常量表达式是指值不会改变并且_在编译过程就能得到计算结果_的表达式.

字面值属于常量表达式,用常量表达式初始化的const对象也是常量表达式

? 一个对象(或表达式)是不是常量表达式由它的数据类型和初始值共同决定

const int max_files = 20; //常量表达式
const int limit = max_files + 1; //常量表达式
int staff_size = 27; //不是
const int sz = get_size(); //不是

? sz虽然本身是一个常量,但到运行时才能获取它的具体值,所以不是.

constexpr变量

? C++11标准规定,允许将变量声明为constexpr类型以便由编译器来验证变量的值是否是一个常量表达式.声明为constexpr的变量一定是一个常量,而且必须用常量表达式初始化

constexpr int mf = 20; //20是常量表达式
constexpr int limit = mf + 1; //mf + 1是常量表达式
constexpr int sz = size(); //只有当size是一个constexpr函数时才是一条正确的声明语句

一般来说,如果你认定变量是一个常量表达式,那就把它声明成constexpr类型

字面值类型

? 常量表达式的值需要在编译时就得到计算,因此对声明constexpr时用到的类型必须有所限制。因为这些类型一般比较简单,值也显而易见、容易得到,就把它们称为“字面值类型”。

? 到目前为止接触过的数据类型中,算术类型、引用和指针都属于字面值类型。自定义类sales_item、IO 库、string 类型则不属于字面值类型,也就不能被定义成constexpr。其他一些字面值类型将在后面介绍。

指针和constexpr

? 必须明确一点,在constexpr声明中如果定义了一个指针,限定符constexpr仅对指针有效,与指针所指的对象无关:

const int *p = nullptr; //p是一个指向整型常量的指针
constexpr int *q = nullptr; //q是一个指向整数的常量指针

? constexpr指针既可以指向常量也可以指向一个非常量:

constexpr int *np = nullptr; //np是一个指向整数的常量指针,其值为空
int j = 0;
constexpr int i = 42; //i的类型时整型常量
// i和j都必须定义在函数体之外
constexpr const int *p = &i; //p是常量指针,指向整型常量i
constexpr int *p1 = &j; //p1是常量指针,指向整数j
  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2021-11-27 09:48:55  更:2021-11-27 09:51:06 
 
开发: 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年11日历 -2024/11/24 7:02:26-

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