引用(reference)其实本质就是给已存在的变量起了一个别名,它和它引用的变量共用同一块内存空间。
引用的使用方法:类型& 别名 = 引用实体;
但要注意,此处的类型应与引用实体类型保持一致!!!
如下:
int temp = 10;
int& a = temp;
double x = 3.14;
double& y = x;
要给int
型变量temp
定义引用a
,则其类型即int&
,其他类型同理,此处不再赘述。
下面验证引用与引用实体共用内存空间:
int temp = 10;
int& a = temp;//temp的第一个引用
int& b = temp;//temp的第二个引用
int& c = temp;//temp的第三个引用
cout << "temp的地址:" << &temp << endl;
cout << "a的地址: " << &a << endl;
cout << "b的地址: " << &b << endl;
cout << "c的地址: " << &c << endl;
上方代码给变量temp
定义了三个引用a,b,c
,到底是不是共用同一块内存空间,验证如下:
4个地址一致,因此引用的实质就是被引用实体的别名没跑了!
1.引用在定义时必须初始化
2.一变量可以拥有多个引用,就像一个人除了自己的本名外,还会有许多称呼一样。
3.一旦引用被定义,那么该引用不能再引用其他实体。即引用从定义那一刻开始,就和被引用实体绑定在了一起。我们根据这一点也就了解为什么引用必须初始化。#
4. 引用只能绑定在对象上,不能与字面值或表达式的计算结果绑定在一起。如下情形都可以证明:
情形1:变量被const
修饰
const int a = 10;
int& ra = a;
结论:变量一旦被const
修饰,则普通的【类型& 别名 = 引用实体】用法错误!
情形2:
int a = 10;
int b = 20;
int& ra = a + b;
结论:引用不能和表达式的计算结果绑定在一起
情形3:
int& ra = 10;
结论:引用不能和字面常量绑定在一起
But!!!
const int a = 10;
const int& ra = a;
cout << "a的地址:" << &a<<"值:" <<a<<endl;
cout << "ra的地址 " << &ra<< "值:"<<ra<<endl;
这样是可以的!
结论:被引用实体被const
修饰,则引用也要加const
进行修饰。被const修饰意味着什么,无非就是不允许修改。
1.做参数
void Swap(int& x,int& y){
int tmp = x;
x = y;
y = tmp;
}
其实此处的引用完全看成指针,上面的函数等价于
void Swap(int* x, int* y){
int temp = *x;
*x = *y;
*y = temp;
}
2.做返回值
但做返回值这里有坑,我先踩为敬!
int& Add(int x, int y) {
int sum = x + y;
return sum;
}
int main() {
int a = 1, b = 2;
int& res = Add(a, b);
cout <<res<<endl;
return 0;
}
结果没得问题!看来的确可以做返回值,但!不要急着下结论,都说了这里有坑,继续看:
我添加一个Destory()函数,咱们再试一次!
int& Add(int x, int y) {
int sum = x + y;
return sum;
}
void Destory() {
int temp[] = { 3,2,1,45,1,2,745,1,2,4 };
cout << "我要覆盖Add()腾出来的空间" << endl;
}
int main() {
int a = 1, b = 2;
int& res = Add(a, b);
Destory();
cout <<res<<endl;
return 0;
}
哎?按理说,这里应该输出3是不?
你瞧。结果差的远着哩!为什么呢?原因在于sum是Add()里的一个变量,当Add()运行结束,Add()的空间就被释放了,里面定义的所有东西在内存中虽然存在,但随着Add()的运行结束,下一行代码就让Destory()来了!它开了栈帧,鸠占鹊巢,立马把Add()腾出来的空间占用了,原来的数据也被破坏了!sum地址存的3已经被覆盖了,所以结果不是3了。
那引用到底可不可以做返回值?答案不变啊,可以!
我们只需要用static修饰一下就行了
int& Add(int x, int y) {
static int sum = x + y;
return sum;
}
结果对了吧,你想覆盖sum?不好意思,static这位保镖不允许你动它。究其根本,就在于static的特性之一:使局部变量的生命周期变全局变量的生命周期。要是有铁子忘了static的三个特性,可以移步这里:
static详解
最后,总而言之:当函数返回时,出了函数作用域,如果返回对象还未返还给系统,那么就可以用引用返回。否则必须使用传值返回。
1.引用定义时必须初始化,指针则不然
2.引用一旦和对象绑定,则不能再引用其他对象,指针则不然
3.没有NULL引用,存在NULL指针
4.sizeof(引用),返回被引用实体的大小;sizeof(指针),返回值永远都是地址空间所占字节个数(32位平台为4)
5.引用自加,即引用实体自加
指针自加,即指针向后移动一个所指类型的大小
6.存在多级指针,没有多级引用
7.访问方式不同,指针需要显式解引用,引用编译器自己处理。
8.引用与指针相比相对更安全(因为引用不能赋值,出生那一刻就已经决定它是谁了,而指针想是谁就是谁)
9.定义引用不开辟新空间,定义指针需要
以值作为参数或返回值类型,在传参和返回期间,函数不会直接传递实参或者将变量本身直接返回,而是传递实参或者返回变量的一份临时的拷贝,因此用值作为实参或者返回值类型,效率非常低下,尤其当参数或返回值类型非常大时,效率更低。