关于C++ const 的用法介绍

一、引言       

       有时我们希望定义一种变量,它的值不会被改变,可以根据实际需要通过某种方式调整,也可以警惕防止程序一不小心改变这个值,我们以前常用#define来实现这个功能。但是,有时出于某些因素,我们使用 const 对变量类型加以限定。       

const int bufsize=512;   //缓冲区大小

二、const初始化问题

       首先,分析一下const的初始化问题。const类型的对象可以完成大部分非const类型的操作,但在const类型的对象上只能执行不改变其内容的操作。在不改变const对象的操作中就有一种是初始化,也就是说,如果利用一个对象去初始化另一个对象,那么无论是不是const类型都无关紧要。分析几个示例可以发现:

int i=5;
const int ci=i;     //正确:使用i来初始化
const int cj=6;     //正确:使用常量来初始化
int j=ci;        //正确:const类型可以参与不改变值的操作
int k=ci++;      //错误:试图通过修改const类型的值
const int ck;      //错误:没有初始化

 

三、编译器如何处理const类型

 接下来,我们谈论一下const类型的工作原理,这样就可以了解为什么不能修改const类型的值,或是为何定义时必须用一个值来初始化它。

       编译器在编译过程中把用到该变量的地方都替换成对应的值。也就是说,对于引言中bufsize的例子,编译器会找到所有bufsize的地方,然后用512替换。这个似乎和#define类似,但是#define是在预处理过程中替换,而const是在编译过程中替换,如果报错,则会指出错误的变量,方便debug。通过下面的例子可以观察到不同:

#include<iostream>
int main()
{
    const int i=5;
    i++;
    return 0;
}

报错信息: 
error: increment of read-only variable 'i'|
#include<iostream>
#define MAX 5
int main()
{
    MAX++;
    return 0;
}

报错信息:
error: lvalue required as increment operand|

介绍完基础的内容就可以考虑更深层次的用法: 比如const的引用、指针和const等问题

四、const的引用

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

       我们前面讨论的情况下,用作const初始化的对象在const初始化后就与const脱离了关系,就相当于两个不同的变量。比如ci和i,初始化结束后,两个变量之间便没有任何联系,i仍可以修改自己的值,ci不能修改自己的值。

       但是根据我们学习的关于引用的知识(简单理解为一个对象的另一个名字,它们的关系是绑定而不是拷贝),与普通引用不同的是,对常量的引用不能被用作修改它所绑定的对象

int i=6;
const int &ci=i;   //正确:引用及其对应的对象都是常量
i=7;    //正确:i=7  ci=7  利用i修改了ci的值
ci=8;    //错误:ci是对常量的引用
const int &cj=3;    //正确
int &j=3;    //错误:试图让一个非常量引用指向一个常量对象

       注意,与普通引用不同的还有一点,普通引用两个对象类型必须相同。而const引用则不必须,允许为一个常量引用绑定非常量的对象、字面值,甚至一个表达式。

double i=6.6;
const int &ci=i;    //正确:绑定double类型的值,ci=6
int &j=i;    //错误:必须类型相同

     总结一点:只要不通过常量引用来修改对象的值,别的都是合法的。const引用可以用任意可转化类型的变量初始化。

五、指针和const

       指针本身也可以定义为常量,称为 常量指针(const pointer),并且符合const特性。在这里我们讨论两种类型,根据结构就可以分辨出来它们的不同。

(1)指针是一个常量

       这种情况表示一旦初始化完成,指针的值就不会改变,也就是存放在指针中的地址不会改变。

int i=6;
int j=7;
int *const ci=&i;    //正确:初始化常量指针
ci=&j;    //错误:试图改变常量指针的值
i=7;    //正确
*ci=8;   //正确:常量指针具体值可以改变

       但是需要注意,正如上面说的,指针是一个常量,也就是我们可以通过ci或者i直接修改具体值,但只要不修改ci的指针值(注意下图中的情况)。

int k;
int *i=&k;
int *const ci=i;
ci=&k;      //错误:虽然它们地址都一样,但还是不能修改ci的指针值

(2)指针所指的对象是一个常量

      与正常的const类型一样,这种情况下具体对象的值也不能改变。

int i=6;
const int *const ci=&i;
i=7;
*ci=8;    //错误:底层const 不能修改具体值

六、顶层const和底层const

顶层const(top-level const) 指针本身是个常量    更一般的,它也可以表示任意对象是常量

底层const(low_level const) 指针所指对象是一个常量,和指针、引用相关

int i=0;
int *const p1=&i;            //顶层const,不能改变p1的值  
const int ci=42;             //顶层const,不能改变ci的值
const int *p2=&ci;           //底层const,允许改变p2的值
const int *const p3=p2;      //左边是底层const  右边是顶层const
const int &r=ci;             //底层const

七、const成员函数

在学习类时,有一种称为const成员函数的函数,下面给出一个示例:   注意到const的位置在函数参数列表的后面

int getvalue() const
{
    return this->num;
}

const成员函数,不允许函数中修改类成员变量(mutable 类型除外),而一些作为参数的外部变量则可以修改。

猜你喜欢

转载自blog.csdn.net/qq_39786762/article/details/81203478
今日推荐