C++primer第二章2.4节对于const限定符相关内容进行详解

 const限定符

  • const对象一旦创建后其数值就不会被再次改变,因此const对象必须初始化。
  • const对象只在文件中有效
  • 在不同的文件中使用不同的const来定义不同的常量,那么每个文件定义的变量只会在自己所属的文件中有效。如果想让多个文件共享同一个const变量,那么使用关键字extern即可

const的引用

把引用绑定到const对象上,就像绑定到其他对象上一样,称之为对于常量的引用。和普通信用不同,对于常量的引用不能被用于修改它所绑定的对象。

const int ci = 1024;
const int &r1 = ci;//正确,引用及其对应的对象都是常量
r1 = 42;          //错误,r1是对于常量的引用
int &r2 = ci;     //错误,试图让一个非常量去引用一个常量对象  
  • 因为不允许直接为ci赋值,当然也不可以通过引用去改变ci,因此,对于r2的初始化是错误的,假设初始化合法,就可以通过r2来改变他引用的对象的数值,这显然是不正确的。

初始化和对const的引用

  • 引用的类型必须和其所引用对象的类型是一致的,但是有两个例外。1,初始化常量引用时候允许用任意表达式来作为初始化的数值,只要该表达式结果可以转化为引用的类型即可。尤其,允许一个常量引用绑定非常量的对象、字面值甚至是一个一般表达式。

    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是一个普通的非常量的引用

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

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

    int i = 42;int &r1 = i; //引用r1绑定对象iconst int &r2 = i;//r2也绑定对象i,但是不允许通过r2来修改i的数值r1 = 0; //r1并非常量,i的数值修改为0r2 = 0; //错误,r2是一个常量的引用,因此不可以修改引用的元素的数值

指针和const

  • 与引用一样,可以另指针指向常量或者非常量。类似于常量的引用,指向常量的指针不能用于改变其所指对象的数值
  • 要想存放常量对象的地址,只能指向常量的指针。
    const double pi = 3.141592653;   //pi是个常量,它的值不能改变double *ptr = π //错误,ptr是一个普通的指针const double *cptr = π //正确,cptr可以指向一个双精度的常量*cptr = 43;//错误,不能给*cptr赋值
  • 指针的类型必须和所指对象类型一致,但是有两个例外:1,允许令一个指向常量的指针指向一个非常量的对象。
double dval = 3.14;//dval是一个双精度的浮点数,它的数值可以改变
cptr = &dval; //正确,但是不能通过cptr来改变dval的数值

const指针

  • 指针是对象而引用不是,因此就像其他对象类型一样,允许把指针本身定位常量。常量指针必须初始化,而且一旦初始化,它的值(存放在指针中的那个地址)就不可以再改变了。

  • 把*放在const关键字之前用来说明指针是一个常量,即不变的是指指针本身的数值而不是指向的那个值

    int errNum = 0;int *const curErr = &errNum; //curErr一直指向errNumconst double pi = 3.14158;const double *const pip = π //pip是一个指向常量对象的常量指针
  • 遵循从右往左读的思想
  • 离curErr最近的符号是const,意味着curErr本身是一个常量对象,对象的类型由声明符的其余部分决定。声明符的下一个符号是*,意思是curErr是一个常量指针。同理,pip是一个常量指针,指向的对象是一个双精度浮点类型的常量。
  • 指针本身是一个常量并不意味着不能通过指针修改其所指向的数值,能否这样做完全依赖于所指向的对象的类型。例如,如果pip是一个指向常量的常量指针,不论是pip所指的对象值还是pip自己存储的那个地址都不能改变。如果,curErr指向的是一个一般的非常量整数,那么完全可以用curErr来修改errNum的数值。

顶层const

  • 指针本身是一个对象,它又可以指向另外一个对象,因此,指针本身是不是常量以及指针所指的是不是一个常量,是两个相互独立的问题。用名词顶层const表示指针本身是一个常量;而使用名词底层const来表示指针所指的对象是一个常量。
  • 顶层的const可以表示任意的对象是常量,这一点适用于任何数据类型,如算数类型、类、指针等。底层const则与指针和引用等符合类型的基本类型部分相关。
  • 比较特殊的是,指针类型既可以是顶层const也可以是底层const,这一点和其他类型相比区别比较明显。
    int i = 0;int *const p1 = &i; //不可以改变p1的数值,这是一个顶层的constconst int ci = 42;  //不可以改变ci的数值,这是一个顶层的constconst int *p2 = &ci; //可以改变p2的数值,这是一个底层的constconst int *const p3 = p2; //靠右边的是顶层const,靠左边的是底层的constconst int &r = ci; //用于声明的const都是底层const
  • 底层const限制不可以忽视。执行对象的拷贝操作的时候,拷入和烤出的对象具有相同的底层const资格,或者两个对象的数据类型之间能够相互转化,一般来说非常量可以转化为常量,反之不可以。

constexper和常量表达式

  • 常量表达式是指不会改变并且在编译的过程中能得到编译结果的表达式。显然,字面值属于常量表达式,用常量表达式初始化的const对象也是常量表达式。
  • 一个对象或者表达式是不是常量表达式是由它的数据类型和初始值共同决定的。
    const int max_files = 20; //max_files是常量表达式const int limit = max_files + 1; //limit是常量表达式int staff_size = 27;//staff_size不是常量表达式const int sz = get_size();//sz不是常量表达式
  • staff_size的初始值是一个字面值常量,但是由于他的数据类型只是一个普通的int而不是const int,所以他不属于常量表达式。
  • sz本身是一个常量,但是他的具体值直到运行的时候才可以获取到,因此也不是常量表达式。

constexpr变量

  • C++11允许将变量声明为constexpr类型,从而使得编译器来验证变量的数值是否是一个常量的表达式。
  • 声明为constexpr的变量一定是一个常量,而且需要用常量表达式来初始化。
    constexpr int mf = 20; //20是常量表达式constexpr int limit = mf + 1 ;// limit是常量表达式constexpr int sz = size();// 只有当size是一个constexpr函数的时候,才是一条正确的声明语句

字面值类型

  • 常量表达式的值需要在编译的时候就得到计算,因此对声明constexpr时用到的类型必须有所限制。因为这些类型一般比较简单,值也比较明显,将其称之为字面值类型。
  • 算数类型、引用和指针都是属于字面值类型。自定义的类型、IO库、string则不属于字面值类型,即不可以定义为constexpr。
  • 指针和引用可以被定义为constexpr类型,但是他们的初始值会受到严格的限制,constexpr指针的初始值必须是nullptr或者是0,或者是存储于某个固定地址中的对象。
  • 先前指出函数体内部定义的变量一般来说不会存在到固定的地址中,因此constexpr指针不可以指向这种变量。相反,因为存储于函数体外的对象其固定的地址不变,因此可以用于初始化constexpr指针。
  • 其中,允许函数定义一类有效范围超出函数本身的变量,这类变量和定义在函数体之外的变量一样也有固定的地址,因此也可以用于对于constexpr指针的初始化。

指针和constexpr

  • 在constexpr声明中定义了一个指针,限定符号constexpr仅仅对于指针有效,而对于指针所指向的对象本身无效。
    const int *p = nullptr;//p是一个指向整型常量的指针constexpr int *q = nullptr;//q是一个指向整数的常量指针
  • 与其他常量指针相类似,constexpr指针既可以指向一个常量指针,也可以指向一个非常量
const int *np = nullptr;//np是一个指向整数的常量指针,其值为空
int j = 0;
constexpr int i = 42;//i的类型是整型常量
//i和j必须定义在函数体之外constexpr const int *p = &i;//p是常量指针,指向整型常量iconstexpr int *p1 = &j;

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/447063.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

二分法的常见问题

mid(leftright)/2; mid (high - low) / 2 low; 这样写可以防止left right溢出 ,不过数足够大是时候该溢还是溢 为什么要取右边中间数呢?这是因为在区间里 只有 2 个元素的时候,把[left…right]划分成[left…mid - 1]和[mid…right]这两个区间&#x…

演示IPFS的一个完整的流程以及针对部分概念的详解

整体的流程 1,创建ipfs节点 通过ipfs init在本地计算机建立一个IPFS节点本文有些命令已经执行过了,就没有重新初始化。部分图片拷贝自先前文档,具体信息应以实物为准 $ ipfs init initializing IPFS node at /Users/CHY/.ipfs generating 2…

c++ 算法的时间复杂度

一般ACM或者笔试题的时间限制是1秒或2秒。 在这种情況下&#xff0c;C代码中的操作次数控制在 10^7为最佳。 下面给出在不同数据范国下&#xff0c;代码的时间复杂度和算法该如何选择&#xff1a; 1.n≤ 30,指数级别&#xff0c;dis剪枝&#xff0c;状态压缩dp 2.n < 100 &g…

简单工厂模式实现计算器

#include <iostream> #include <vector> #include <string> #include <iostream> #include <map> using namespace std; #define __THROW_ZERO do {cerr << "The dividend is 0" << endl; exit(1);}while(0);/* 简单工厂处…

TDengine安装教程

TDengine安装教程 前言 TDengine的安装十分简单&#xff0c;可以有以下三种安装方式&#xff0c;源码安装、通过Docker容器进行安装、通过安装包进行安装。但是使用源码安装较为复杂&#xff0c;通过docker的方式最为简单&#xff0c;但是需要一定docker相关的知识&#xff0…

C++中size_t的学习

size_t的定义 size_t是一种数据相关的无符号类型&#xff0c;它被设计得足够大以便能够存储内存中任意对象的大小。设计 size_t 就是为了适应多个平台&#xff0c;size_t等效于unsigned short int 或者 unsigned long int 类型&#xff0c;这个过程是动态匹配的。在需要通过数…

策略模式解决商店打折问题

#include <bits/stdc.h> using namespace std; /*策略模式解决商店打折问题*/class Cashsuper { private:/* data */ public:virtual double addcash(double cash) 0;double Getresult(double money){return addcash(money);} };class Cashnormal : public Cashsuper {p…

android 软件首次运行时引导页左右滑动效果

很多手机软件在安装后首次运行都会进入到引导页面&#xff0c;再次运行时会进入到主页面。 多了不说了&#xff0c;先看效果图&#xff1a; 代码如下&#xff1a; main.xml <?xml version"1.0" encoding"utf-8"?> <RelativeLayout xmlns:an…

C++中size_type类型详解

介绍 是和string类类型和vector类类型定义相关的类型&#xff0c;用以保存任意string对象或vector对象的长度&#xff0c;标准库类型将size_type定义为unsigned类型string抽象意义是字符串&#xff0c; size&#xff08;&#xff09;的抽象意义是字符串的尺寸&#xff0c; str…

单一职责原则 实现贪吃蛇代码的封装

单一职责原则(SRP),就一个类而言&#xff0c;应该仅有一个引起它 变化的原因。 一个c语言的贪吃蛇代码 如何使用单一职责原则封装成c面向对象呢 #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<string.h> #include<stdlib.h> #include <wi…

android ProgressBar实现扫描SD卡文件 + SimpleAdapter绑定ListView

代码 activity_main.xml <RelativeLayout xmlns:android"http://schemas.android.com/apk/res/android"xmlns:tools"http://schemas.android.com/tools"android:layout_width"match_parent"android:layout_height"match_parent"to…

C++标准库函数begin和end函数

主要的目的 为了让指针更加简单、安全&#xff0c;引入了begin和end函数&#xff0c;这两个函数和容器中两个同名的成员函数类似。但是由于数组毕竟不是类类型&#xff0c;因此这两个函数不是成员函数。正确的使用形式就是将数组作为他们的参数int ia[] {0,1,2,3,4,5,6,7,8,9…

dex分包之--------multidex包的配置使用

目录&#xff1a;一、前言二、产生原因三、MultiDex的简要原理四、MultiDex的使用 一、前言 首先说一下我遇到的情况&#xff0c;最近接手了一个项目是在已有的项目里进行更新添加一些功能&#xff0c;然后该项目导了N多的包&#xff0c;在我使用Android Studio的run”App”直…

C++ primer第六章函数的学习

介绍 首先介绍函数的定义和声明&#xff0c;包括如何传入参数以及函数如何返回结果。C语言允许使用重载函数&#xff0c;即几个不同的函数可以使用向同一个名字。所以接下来介绍重载函数的方法&#xff0c;以及编译器选择如何从函数的若干重载的形式中选取一个与调用模板相互匹…

C语言指针作为函数参数 以及智能指针作为函数参数

总所周知指针作为函数参数传递的时候 传递的是指针的拷贝&#xff08;指针也是变量&#xff09; 这里提供四种指针的传递方法 改到实际的指针。 #include <stdio.h> #include <memory> #include <iostream> using namespace std; void test1(char **string)…

Android Studio打包和引用aar

一、简介 Android 库在结构上与 Android 应用模块相同。它可以提供构建应用所需的一切内容&#xff0c;包括源代码、资源文件和 Android 清单。不过&#xff0c;Android 库将编译到您可以用作 Android 应用模块依赖项的 Android 归档 (AAR) 文件&#xff0c;而不是在设备上运行…

C++ primer第六章6.4函数的学习 之函数的重载

6.4 函数的重载 函数的名字相同但是形参的列表不同&#xff0c;将其称之为重载函数 void print(const char *cp); void print(const int *beg,const int * end); void print(const int ia[],size_t size); 形如上面所展现的这样&#xff0c;当调用这些函数的时候&#xff0c;…

C++有限状态机的实现

//待完善 有限状态机是一个很常用的技术&#xff0c;在流程控制和游戏AI中都比较实用&#xff0c;因为状态机编程简单又很符合直觉。与有限状态机类似的是设计模式中的状态模式。本文是参考《Programming Game AI by Example》 一、 记得最开始工作时候也接触过有限状态机&…

手势希尔排序

void shell_sort(int *data, int length){int gap0;int i0,j0;for(gaplength/2;gap>1;gap/2){//组内插入排序for(igap;i<length;i){int temp data[i];for(ji-gap;j>0&&temp<data[j];jj-gap){data[jgap]data[j];}data[jgap]temp;}} }