C++ 关键字:const 详解

it2026-01-04  9

《C++ Primer 第五版》读书小笔记

const 限定符

1. 简介

   当我们需要一种变量,它的值不能被改变的情况下,就会使用const对变量的类型加以限定。任何意图修改或可能修改该变量的值的行为都将引发错误。

2. const 的 初始化

   因为const对象一旦创建后其值无法被改变,所以const对象必须被初始化。

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

  当以编译时初始化的方式定义一个const对象时,编译器将在编译过程中把用到该变量的地方都替换成对应的值。   默认情况下,const对象被设定为仅在文件内有效。当多个文件中出现了同名的const变量时,其实等同于在不同文件内中分别定义了独立的变量。   若想只在一个文件内定中定义const,并且在其他文件中声明并使用它的解决方法是:对于const变量无论是定义还是声明都添加extern关键字。

/*file.cpp*/ extern int buffersize = get_value();//定义并初始化一个常量,且该常量可以被其他文件访问 /*file.h*/ extern int buffersize ; //声明该常量可以在其他文件中获取定义,在这里等同于file.cpp里的常量

3.const的引用

  可以把引用绑定到const 对象上,就像绑定到其他对象上一样,称之为对常量的引用。与普通引用不同的是,对常量的引用不能被用作修改它所绑定的对象。   const引用的初始化:     特别注意:允许为一个常量引用绑定非常量的对象、字面值甚至一个一般表达式。     常量引用仅对引用可参与的操作做出了限定,对于引用的对象本身是否是一个常量不做限定。因为对象可能也是一个非常量,所以允许通过其他途径修改其值。

4.指针与const

  指针与const中最容易混淆的两个概念:

指向常量的普通指针 :不可以通过该指针修改该变量的值,因为const让指针觉得他指向的就是一个常量,所以指针就不能去修改。(当然如果该变量是非常量,则可以通过其他路径去修改是可以的) int i = 2;//非常量i const int *p =&i;//指向常量的指针p(p自己觉得自己指向的是一个常量) *p = 3; //错误,不能通过该指针去修改i的值 i = 3; //正确,但可以通过其他途径去修改 指向变量的常量指针:不可以修改指针的指向,指针的指向就是指针这个对象的值,这个指针是个常量,那必然不可能让你去修改的 int j = 2; //非常量 j int * const p =&j; // 指向变量的常量指针 p *p = 3; //可以修改j的值 int k = 42;//另一个非常量k p = &k;//不可以修改p的指向,因为指针自身为常量

  这两者的最大区别就是这两个常(const)的修饰对象分别为变量和指针。并且这两种形式都不关心所指向的对象是否真的为常量。只要把这店理解清楚,就很难混淆了。(代码上理解法则:看距离变量最近的那个修饰符是*还是const)   当然这两者是相互独立的,所以也可以叠加到一起:

int i = 10; const int *const p = &i ;//指向常量的常量指针p,不可以通过p修改i,也不可以修改p的指向。

5. 顶层const与底层const

  如前所述,指针本身是一个对象,它又可以指向另外一个对象。因此,指针本身是否为常量以及指针所指的是不是一个常量就是连个相互独立的问题。用名词顶层const表示指针本身是个常量,用名词底层const表示指针所指的对象是一个常量。   更一般的,顶层const可以表示任意对象是常量,而底层const则与指针和引用等复合类型的基本类型部分有关(即为const修饰的为更底层的对象)。   特殊:指针既可以是顶层const也可以是底层const。

int i = 0; int *const p1 = &i ; // 顶层const,修饰指针p1为常量 const int c1 = 42; //顶层const ,修饰c1为常量 const int *p2 = &c1; //底层const,修饰p2所指的对象c1为常量 const int *const p3 = p2; //左const为底层const修饰p3所指向的p2为常量,右const为顶层const修饰p3为常量 const int &r = ci; //底层const修饰ci为常量

执行对象的拷贝操作时两种const的差异:

底层const:当执行对象的拷贝操作时,拷入和拷出的对象必须具有相同的底层const资格或者两个对象的数据类型必须能够转换(非常量可以转换为常量)。顶层const:不受影响 对于这种差异的产生,也请深刻理解简介里说的: 任何意图修改或可能修改该变量的值的行为都将引发错误。

5. constexpr和常量表达式

常量表达式:是指值不会改变并且在编译过程就能得到计算结果的表达式。例如字面值、用常量表达式初始化的const对象。 问题:const对象的初始值我想让他是一个函数该咋办呢?c++11的constexpr就起作用了。 constexpr:c++11新标准规定,允许将变量声明为constexpr类型以便由编译器来验证变量的值是否是一个常量表达式。声明为constexpr的变量一定是要给常量,而且必须用常量表达式初始化:

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

constexpr函数:定义constexpr函数与其他函数类似,但是要求:函数返回值类型及所有形参的类型都得是字面值类型,且函数体中必须有且仅有一条return语句。 字面值类型:算术类型(整型、浮点型…),引用以及指针都属于字面值类型,而自定义类,IO库,string等等则不属于字面值类型。 constexptr指针:constexpr指针的初始值必须是nullptr或者0或者存储与某个固定地址的对象(定义于所有函数体之外的对象或者允许函数定义一类有效范围超出函数本身的变量)。 特殊 :限定符constexpr仅对指针有效,与指针所指对象无关:

const int *p =nullptr; //p为一个指向常量的指针 constexpr int *q = nullptr; //q为一个常量指针

总结

  以上内容对于c++中的const限定符的主要用法做了一些整理归纳,对于一些易混淆点做了区分。以及简单介绍了c++11中引入的constexpr限定符。   欢迎评论和指正!

最新回复(0)