对const的引用

定义

就像被绑定到其他对象上一样,我们能够将引用绑定到一个const类型的对象上,这种行为被称之为使用了一个对const对象的引用。与普通引用不同的是,对const的引用不能被用来修改它所绑定的对象。例如:

    const int ci = 1024;
    const int &r1 = ci;    // 正确,引用和引用的对象都是const
    r1 = 42;               // 错误,r1是一个对于const的引用
    int &r2 = ci;          // 错误,非const引用不能引用const对象

const引用与对const的引用区分

C++程序员常常把“对const的引用”简称为“const引用”。从实质上说,并没有const引用。因为引用不是一个对象,所以我们不能使引用本身变为const。然而,因为一个引用本身是不能够改变其所绑定的对象的,从某种程度上说,所有的引用又都是const的。因此,一个引用是引用了一个const类型还是一个非const类型只会影响我们对这种引用所能够执行的操作,而不会影响到引用绑定关系的本身。(翻译自C++ Primer, Fifth Edition)

简单来说,就是,“const引用”本身是不存在的,本质上说所有的引用都是const(不能改变的),引用类型是否是const只会影响到相应的操作权限。

初始化和对const的引用

我们知道,引用的类型必须与其所引用的对象的类型一致。这里有例外,这个例外就是我们能够初始化一个对const的引用来引用一个可以转换成引用类型的对象,特别的,我们能够将一个对const的引用绑定至一个非const的对象、字面值常量或者更加一般的表达式:

    int i = 42;
    const int &r1 = i;        // const int&能够绑定至一个普通的int对象
    const int &r2 = 42;       // 正确,r1是一个对const的引用
    const int &r3 = r1 * 2;   // 正确,r3是一个对const的引用
    int &r4 = r1 * 2;         // 错误,r4是一个普通的非const引用

我们以一个具体的例子解释这其中发生了什么:

    double dval = 3.14;
    const int &ri = dval;

这里ri引用了一个int,对于ri的操作本应该是一个整型运算,但是dval是一个浮点数,而不是整型。为了确保ri确实是绑定于一个int,编译器将会将如上的代码改变成如下形式:

    const int temp = dval;      // 使用dval创建一个临时的整型常量
    const int &ri = temp;       // 将ri绑定至这个临时量

好了,我们现在再考虑一下如果这个引用不是对const的引用,能否正确。如果ri不是const,我们就能够对ri进行赋值操作。这样的话,我们就会改变ri所引用的对象,然而这个被改变的对象是临时量,而不是dval本身,显然不合本意。因此如果这个引用不是对const的引用就是非法的操作。

对const的引用可能引用一个不是const的对象

这里,必须要理解到:对const的引用只会限制我们通过这个引用所能够做的事情(即通过这个const的引用对原对象的操作权限)。将一个对const的引用绑定到一个对象并没有要求这个对象本身就是const,因为这个被绑定的对象本身就可能是一个非const类型,它可以通过其他的方式改变它的值,例如:

    int i = 42;                
    int &r1 = i;                 // r1绑定i
    const int &r2 = i;           // r2也绑定i,但是不能使用r2改变i
    r1 = 0;                      // r1不是const,可以改变,现在i和r2都是0
    r2 = 0;                      // 错误,r2是一个对const的引用,不能通过其改变绑定对象

最后总结一下,将r2绑定至一个(非const的)变量i是合法的,只是我们不能使用r2来改变i的值,i的值可以通过自身改变或者其他非cont的引用改变,例如r1。

posted @ 2020-03-15 17:19  southernEast  阅读(397)  评论(0编辑  收藏  举报