C++ 常量引用用法详解
“常量引用”其实是“对 const 的引用”的简称。
顾名思义,它把它所指向的对象看作是常量(不一定是常量),因此不可以通过该引用来修改它所指向的对象的值。
严格来说,并不存在常量引用,因为引用不是一个对象,所以我们没法让引用本身恒定不变。事实上,由于 C++ 语言并不允许随意改变引用所绑定的对象,所以从这层意思上理解所有的引用又都算是常量。
与普通引用不同的是,“常量引用”(即对 const 的引用)不能被用作修改它所绑定的对象。
(1)指向常量对象时,一定要使用“常量引用”,而不能是一般的引用。
因为不允许直接为常量赋值,当然也就不能通过引用去改变常量。因此直接规定当引用一个常量时,必须使用“常量引用”。
const int ci = 1024;
const int &r1 = ci; // 正确:引用及其对应的对象都是常量
r1 = 42; // 错误:r1是对常量的引用,不能被用作修改它所绑定的对象
int &r2 = ci; // 错误:试图让一个非常量引用指向一个常量对象
(2)“常量引用”可以指向一个非常量对象,但不允许用过该引用修改非常量对象的值。
必须认识到,“常量引用”仅对引用可参与的操作做出了限定,对于引用的对象本身是不是一个常量未作限定。因为对象也可能是个非常量,所以允许通过其他途径改变它的值:
int i = 42;
int &r1 = i; // 普通引用指向非常量对象 i
const int &r2 = i; // 常量引用也绑定非常量对象 i
r1 = 0; // 正确,r1并非常量引用
r2 = 0; // 错误:r2是一个常量引用
r2
绑定非常量整数 i
是合法的行为。然而不允许通过 r2
修改 i
的值。尽管如此,i
的值仍然允许通过其他途径修改,既可以直接给 i
赋值,也可以通过像 r1
一样绑定到 i
的其他引用来修改。
(3)引用的类型必须和所引用的类型严格匹配,且不能与字面值或者某个表达式的计算结果绑定在一起,但是 “常量引用” 是例外(只要被引用的类型能够转换为常量引用的类型)。
尤其,允许为一个常量引用绑定非常量的对象、字面值,甚至是一个一般表达式:
int i = 42;
const int &r1 = i; // 正确:指向非常量对象
const int &r2 = 42; // 正确:r2 是一个常量引用
const int &r3 = r1 * 2; // 正确:r3 是一个常量引用
int &r4 = r1 * 2; // 错误:r4 是一个普通的非常量引用
下面的操作也是允许的:
double dval = 3.14;
const int &r1 = dval;
此处 const int &r1 = dval
编译器实际上相当于执行了下列语句:引用和原 dval
已经不是同一个地址了:
const int temp = dval; // 生成一个临时的整型常量
const int &r1 = temp; // 让 r1 绑定这个临时量
在这些情况下,“常量引用”实际上是绑定了一个临时量(temporary)对象。也就是说,允许“常量引用”指向一个临时量对象。
当 r1
不是“常量引用”时,如果执行了类似于上面的初始化操作会带来什么样的后果?
如果 r1
不是常量,就允许对 r1
赋值,这样就会改变 r1
所引用的对象的值。注意,此时绑定的对象是一个临时量而非 dval
。程序员既然想让 r1
引用 dval
,就肯定想通过 r1
改变 dval
的值,否则干什么要给 r1
赋值呢?如此看来,既然大家基本上不会想着把引用绑定到临时量上,C++ 语言也就把这种行为归为非法。
也就是说,不允许一个普通引用与字面值或者某个表达式的计算结果,或类型不匹配的对象绑定在一起,其实就是不允许一个普通引用指向一个临时变量,只允许将“常量引用”指向临时对象。
(4)在函数参数中,使用常量引用非常重要。因为函数有可能接受临时对象,而且同时需要禁止对所引用对象的一切修改。
下面程序执行发生错误,因为不可以将一个字面值常量赋值给普通引用;函数的返回值如果是非引用类型时,实际上是作为一个临时变量返回的,经过上面的讨论,不允许一个普通引用指向临时对象。
int test() {return 1;
}void fun(int &x) {cout << x << endl;
}int main()
{int m = 1;fun(m); // okfun(1); // errorfun(test()); // errorreturn 0;
}
按下面修改后,fun()
函数无论是接受字面值常量作为参数,还是将函数的返回值作为参数均可:
int test() {return 1;
}void fun(const int &x) {cout << x << endl;
}int main()
{fun(1); // okfun(test()); // okreturn 1;
}
C++ 常量引用用法详解相关推荐
- c语言常量的正确表示const,C语言中的const和free用法详解
注意:C语言中的const和C++中的const是有区别的,而且在使用VS编译测试的时候.如果是C的话,请一定要建立一个后缀为C的文件,不要是CPP的文件.因为,两个编译器会有差别的. 一.C语言中的 ...
- C++/C--unordered_map常见用法详解
文章目录 1. std::unordered_map 的定义与特性 2. 构造 std::unordered_map 3. 赋值操作 4. 迭代器操作 4.1 指向整个容器中的元素 4.2 指向某个桶 ...
- BigDecimal的用法详解(保留两位小数,四舍五入,数字格式化,科学计数法转数字,数字里的逗号处理)
一.简介 Java在java.math包中提供的API类BigDecimal,用来对超过16位有效位的数进行精确的运算.双精度浮点型变量double可以处理16位有效数.在实际应用中,需要对更大或者更 ...
- STL迭代器(iterator)用法详解
C++ STL迭代器(iterator)用法详解 无论是序列容器还是关联容器,最常做的操作无疑是遍历容器中存储的元素,而实现此操作,多数情况会选用"迭代器(iterator)"来实 ...
- Find_in_set()函数的使用及in()用法详解
这篇文章主要介绍了mysql中find_in_set()函数的使用以及in()用法详解,需要的朋可以参考下 MySQL手册中find_in_set函数的语法解释: FIND_IN_SET(str,st ...
- C++中的unordered_map常见用法详解
文章目录 1. std::unordered_map 的定义与特性 2. 构造 std::unordered_map 3. 赋值操作 4. 迭代器操作 4.1 指向整个容器中的元素 4.2 指向某个桶 ...
- #ifdef,#else,#endif,#if用法详解(转)
#ifdef,#else,#endif,#if用法详解(转) 2011-04-22 10:11 预处理就是在进行编译的第一遍词法扫描和语法分析之前所作的工作.说白了,就是对源文件进行编译前,先对预处理 ...
- Oracle中游标Cursor基本用法详解
这篇文章主要介绍了Oracle中游标Cursor基本用法详解,还是比较全面的,具有一定参考价值,需要的朋友可以了解下. 查询 SELECT语句用于从数据库中查询数据,当在PL/SQL中使用SELECT ...
- Python函数(函数定义、函数调用)用法详解
函数 函数就是一段封装好的,可以重复使用的代码,它使得我们的程序更加模块化,不需要编写大量重复的代码. 函数可以提前保存起来,并给它起一个独一无二的名字,只要知道它的名字就能使用这段代码.函数还可以接 ...
最新文章
- Cocos事件监听(JS)
- AngularJS ui-router (嵌套路由)
- 网页性能优化04-函数节流
- nginx配置文件【转载】
- POJ3398 Perfect Service
- html5 查看图片,html5实现图片预览和查看原图
- PWM调光方法在LED亮度调节中的应用
- Java 反射(初步)
- java怎么部署_java项目服务器如何部署?项目服务器的部署步骤
- Windows下本地安装SVN客户端
- 超市仓库管理系统python+tkinter
- Linux大实验 (图书管理系统)
- python pandas 教程下载_如何用Python处理Excel?Pandas视频教程官方文档来啦~
- Error opening zip file or JAR manifest missing
- 11210怎么等于24_所有能算24点的四个数,(4个数只能是1——10之间的数)我举个例:1,1,1,8.1,1,2,6.………………所有能算...
- Turing Tape (推公式 模拟)
- Diffusion Models专栏文章汇总:入门与实战
- Python数字图像处理---1.1图像的像素格式与图像读写
- 白鹭引擎王泽:重度H5游戏性能优化技巧
- Android自定义底部带有动画的Dialog