首页 > 编程语言 > 详细

C++中的const限定符部分特性

时间:2020-05-11 09:04:47      阅读:87      评论:0      收藏:0      [点我收藏+]

const限定符

1 const对象仅在文件内有效

  • 当编译时以初始化的放视定义一个const对象时,例如const int bufSize = 512;,编译器将在编译过程中把用到该变量的地方都替换成对应的值,也就是说,编译器会找到代码中所有用到bufsize的地方,然后用512替换
  • 在这个过程中,编译器必须知道变量的初始值,但是如果程序包含多个文件,每个用到了const对象的文件都必须得能够访问它的初始值才可以,这就使得每一个用到该变量的文件都有它的定义。
  • 同时,为了避免同一个变量的重复定义,默认情况下,const对象被设定为仅在文件内有效,当多个文件出现同名const变量时,等同于不同文件中分别定义了独立的变量。
  • 如果我们想和使用非常量一样使用const,使得一个const变量可以在文件间共享,也就是在一个文件中定义const,别的文件通过声明使用它。方法是对于const变量不管声明还是定义都添加extern关键字,这样就只需要定义一次。
//定义并初始化了bufSize,因为他是一个常量,必须使用extern使其可以被其他文件使用
extern const int bufSize = fcn();
//此处下面的bufSize则是一个声明
extern const int bufSize;

2 const的引用

  • 对常量的引用不能呗用作修改它所绑定的对象
const int a = 1024;
const int &b = a; //引用及其对象都是常量
b = 42; //错误,b是对常量的引用
int &c = b; //错误,试图让非常量引用指向常量对象

因为不允许改变a的值,因此也不能通过引用的方式去改变它,所以引用他的也一定是常量

3 初始化和对const的引用

引用的类型必须与其所引用对象的类型一致,只有两个例外,这里说其中一个

  • 初始化常量引用允许用任意表达式作为初始值,只要该表达式能转换成引用的类型,允许为一个常量引用绑定非常量的对象、字面值甚至是一个一般表达式
int i = 42;
const int &a = i; //正确,允许将一个const int&绑定到普通int对象
const int &b = 42; //正确,b是一个常量引用
const int &c = a * 2; //正确,c是一个常量引用
int &d = a * 2; //错误,r4是一个非常量引用
  • 本质上来说,const int &c = a * 2 这个语句,为了确保c可以绑定到一个数,编译器采用的方法是将他变为·int tmp = a * 2; const int &c = tmp,这样,c就绑定了一个临时量对象,所谓临时量对象就是编译器需要一个空间来暂存表达式的求职结果时候创建的未命名对象。
  • 同时,当d定义为非常量的时候,就允许修改d,但是修改d的左右时修改临时量的值而非表达式的值,这样的情况下修改d就毫无意义,因此C++将这样的行为归为非法

4 对const的引用去引用一个非const对象

int i = 42;
int &a = i;
const int &b = i;
a = 0; //正确
b = 0; //错误,因为b是一个常量引用

如上,用一个常量引用去引用一个非常量对象,作用是使得不能通过修改引用的方式修改对象的值,但是依然可以通过其他的方法,比如直接给i赋值的行为,去修改对象的值

5 指针和const

  • 和引用类似,指向常量的指针不能用于改变其所指对象的值,想要存放常量对象的地址,只能使用指向常量的指针
const double PI = 3.14;
double *ptr = Π    //错误,ptr不是常量指针,是普通指针
const double *dptr = Π //正确,dptr是一个常量指针
*dptr = 42;   //错误,不能给*dptr赋值
  • 指针的类型必须与所指对象的类型一直,和引用一样,也有两个例外,一个就是允许常量指针指向非常量对象
  • 指向常量的指针没有规定所指对象是常量,仅仅是要求不能通过该指针改变对象的值,而没有规定那个对象不能通过其他途径改变

所谓常量指针,常量引用,可以理解为指针和引用自以为指向了一个常量,所以自觉地不去改变对象的值

6 const 指针

  • 指针是对象,但是引用不是,所以和引用不同的是,允许把指针本身定为一个常量。
  • 常量指针必须初始化,并且一旦初始化完成,他的值(也就是存放在指针里的地址就不能改变了),把*放在const之前说明指针是一个常量,代表不变的是指针本身而非他指向的值
int errNum = 0;
int *const curErr = &errNum;  //一个指向errNum的常量指针
const double PI = 3.14159;
const double *const pip = *pi;
  • 弄清楚声明最行之有效的方式是从右往左,例如对于pip而言,首先可以从const得知这是一个常量对象,然后从*得知这是一个常量指针,然后从const double得知这是一个指向类型为const double的常量指针
  • 常量指针并不意味着不能通过指针修改它指向的值,能否修改完全取决于对象的类型

7 顶层const

  • 根据5.5,5.6得知,指针本身是不是常量和指针指向的是不是常量是两个相互独立的问题,用名词顶层表示指针本身是个常量,底层表示指针所指的对象是个常量
  • 更一般的,顶层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 int的常量指针,靠右的const是底层const,靠左的是顶层const
const int &r = ci; //指向const int的引用,底层const
  • 当执行对象的拷贝操作时,常量是顶层const和底层const的区别明显,其中顶层const不收什么影响
  • 但是底层const的限制却不能忽视,当执行对象拷贝操作时,拷入拷出的对象必须具有相同的底层const资格,或者两个对象的数据类型可以相互转换,非常量可以转化为常量,反之则不行
i = ci;  //拷贝ci的值,ci是一个顶层const,无影响
p2 = p3; //拷贝p3的值,p2和p3指向的对象类型相同,p3顶层const不受影响

int *p = p3;  //错误,p3包含底层const定义,p没有
p2 = p3; //正确,p2,p3都是底层const
p2 = &i; //正确,int*可以转化为const int *
int &r = ci; //错误,r没有底层const
const int &r2 = i; //可以,const int &可以绑定在普通int上

8 常量表达式

  • 常量表达式是指值不会改变并且在编译过程中就得到了计算结果的表达式,显然字面值属于常量表达式,用常量表达式初始化的const对象也是常量表达式
  • 一个对象(或者表达式)是不是常量表达式由它的数据类型和初始值共同决定,例如
const int max_files = 20;  //是常量表达式
const int limit = max_files + 1;  //是常量表达式
int staff_size = 27; //不是常量表达式,因为staff_size不是常量
const int sz = getsize(); //不是常量表达式,因为getsize()不是常量

9 constexpr 变量

  • 在一个复杂系统中,很难分辨一个初始值到底是不是常量表达式。C++11中规定,允许将变量声明为constexpr类型以便由编译器来验证变量的值是否是一个常量表达式
  • 声明为constexpr的变量一定是一个常量,并且必须使用常量表达式初始化
constexpr int mf = 20; //20是常量表达式
constexpr int limie = mf + 1; //mf + 1是常量表达式
constexpr int sz = size(); //只有当size()是一个constexpr函数时才是一条正确的声明语句
  • 一般来说,如果认定一个变量是常量表达式,就把他声明为constexpr类型
  • 因为常量表达式的值需要在编译时得到计算,因此对声明constexpr时用到的类型必须有所限制,这些类型一般比较简单和显而易见,称为字面值类型
  • 算术类型,引用和指针都属于字面值类型,自定义类,IO库,string类型等不属于字面值类型,因此不能定义为constexpr
  • 尽管指针和引用都能定义为constexpr,但是他们的初始值受到严格限制,一个constexpr指针的初始值必须是nullptr或者0或者是存储于某个固定地址的对象
  • 如果constexpr声明中定义了一个指针,限定符constexpr仅对指针有效,与指针所指的对象无关
const int *p = nullptr; //p是一个指向整型常量的指针
constexpr int *q = nullptr; //q是一个指向整数的常量指针

其中关键在于constexpr把他定义的对象置为了一个顶层const

constexpr int *np = nullptr; //np是一个指向整型的常量指针
int j = 0;
constexpr int i = 42;  //i是一个整型常量
constexpr const int *p = &i; //p是一个指向整型常量的常量指针
constexpr int *p1 = &j;   //p1是一个指向整形的常量指针

文章内容参考C++ Primer

C++中的const限定符部分特性

原文:https://www.cnblogs.com/Hugh-Locke/p/12866856.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!