什么是引用?
引用是在C++2.0版本引入的。
引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量一直绑定在一起共用同一块内存空间。
一般情况,引用具有以下性质。
- 1.引用不是一个变量,只是一个已存在变量的别名。
int a = 10;
int& ra = a;//ra是a的引用
//sizeof(ra) == sizeof(a)
ra = 20;//对ra操作赋值,则相当于对a赋值。
- 2.可以有多个引用与同一个已存在变量绑定到一起。
int a = 10;
int& ra1 = a;
int& ra2 = a;
int& ra3 = a;//ra1,ra2,ra3都是a的别名
- 3.引用不是一个变量,不能定义引用的引用,不能定义指向引用的指针
int& rra = ra;//错误。
int *p = ra;//错误
- 4.由于要和某一变量绑定,所以引用必须初始化。
int& ra;// error C2530: “ra”: 必须初始化引用
- 5.引用的类型要和与之绑定的变量类型严格匹配。
int a = 10;
float& fa = a;//error C2440: “初始化”: 无法从“int”转换为“float &”
- 6.引用绑定后,将一直与变量绑定在一起,所以引用不能再重新绑定到另一变量。
int a = 10;
int b = 20;
int& ra = a;
&ra = b;//错误,无法重新绑定
注:数组可以引用,只是写法和一般不同
int b[10] = {0};
int (&rb)[10] = b;
Const的引用
引用除了可以和变量绑定外,还可以绑定到const对象上,称之为“对常量的引用”。所以,对常量的引用,不能修改它所绑定的对象。
提示:常量引用是其实对const的引用,因为引用本身不是一个对象。
const int a = 10;
const int& ra = a;//对const修饰的变量a的引用
ra = 20;//错误,ra试图修改与它绑定对象的值。
int& ra2 = a;//错误,试图让一个非常量引用绑定到一个常量上。
前面提到,引用的类型必须和其绑定对象的类型一致,但是,C++允许一个常量引用绑定到非常量的对象、字面值,甚至是一个表达式。
int a = 10;
const int b = 20;
const int& ra = a;//允许将const int&绑定到一个普通int对象上
const int& rb = b;//rb是一个常量引用。
const int& r1 = ra*rb;//r1是一个常量引用
int& r2 = r1*3;//错误:r2是一个非常量引用。
为什么会出现上面的特例呢?
观察下列代码,判断编译器对于i1和i2的理解。
double d = 20.0; int& i1 = d;//error C2440: “初始化”:
无法从“double”转换为“int &” const int& i2 = d;//warning C4244: “初始化”:
从“double”转换到“constint”,可能丢失数据
分析:
第一句话,错误提示:无法从double转换为int &,我们都理解,是因为类型不同。
但是第二句话,不是错误提示:无法从double转换为const int &呢?确实警告double转换为const int有数据丢失。
说明,编译器帮我做了隐式转化,将double转化为const int,然后等号左右两类型相同,自然通过编译。
转化过程:这里编译器对代码进行插手了,为了确保让i2绑定到一个整型,编译器隐式转化,用double类型d 生成了一个临时对象const
int,(临时对象具有常性)。将r2指向了临时对象。对const的引用可能引用一个非const对象。此时可以通过特殊手段改变const引用的值。
int a = 10;
const int& ra1 = a;//常量引用
int& ra2 = a;//非常量引用
ra1 = 20;//错误,无法修改
ra2 = 20;//正确,可以修改
引用作为参数或返回值
对引用的操作就是对其绑定对象的操作,所以引用可以作为参数或返回值。
引用作为参数和返回值具有和指针一样的效率但是比指针更安全,操作更方便。
原因下面描述。
引用和指针的区别
想到搞清楚引用与指针的区别,要先看看编译器是如何看待他俩的工作原理
#include <iostream>
int main()
{
int a = 10;
int& ra = a;
int* pa = &a;
return 0;
}
看其汇编
a;
012D13C5 lea eax,[a]
012D13C8 mov dword ptr [ra],eax
int* pa = &a;
012D13CB lea eax,[a]
012D13CE mov dword ptr [pa],eax
可以发现,编译器对指针和引用的看待方式相同,即引用被当做指针来看待。 所以:我们一般将int& ra = a与nt *const ra =
a;是等效的。虽然两者在底层上的实现是相同的,都是当做指针来使用。
但是,在语言层面两者还是有很大的不同。
根据对引用的描述和指针的概念比较可以的出以下结论
- 1、引用在定义时必须初始化,指针没有要求。
- 2、一旦一个引用被初始化为指向一个对象,就不能再指向其他对象,而指针可以在任何时候指向任何一个同类型对象
- 3、没有NULL引用,但有NULL指针。
- 4、在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数。
- 5、引用自加改变变量的内容,指针自加改变了指针指向
- 6、有多级指针,但是没有多级引用
- 7、引用比指针使用起来相对更安全