C++的引用具备指针的所有功能,不过引用与指针的区别在于引用在定义时必须要初始化,因为引用对象不许为空,若对象可以为空,则定义指针变量,int i=9;int &s = i;
定义引用指向了i;其实引用相当于我们所说的"别名",是所指向的变量的别名,引用与变量共用一个内存地址
如:
- int a ;
- int &b = a;
int a ;
int &b = a;
他们的内存地址都是一块地址
只要内存地址的值发生改变,这两个变量的值都会改变,下面可以验证一下
代码
- #include <iostream>
- using namespace std;
- int main()
- {
- int a ;
- int &b = a;
- a = 100; //内存地址值得改变,变量b的值也变
- cout << "b = " << b <<endl;
- b = 200;//a的值也变
- cout << "a = " << a << endl;
- return 0;
- }
#include <iostream>
using namespace std;
int main()
{
int a ;
int &b = a;
a = 100; //内存地址值得改变,变量b的值也变
cout << "b = " << b <<endl;
b = 200;//a的值也变
cout << "a = " << a << endl;
return 0;
}
执行的结果:
当一个引用初始化时指定到了一个变量,则这个引用的地址永远是该变量的地址,不会再改变,如果该引用再次指向别的变量,则只是把这个变量的值赋给该引用,
引用的地址不会改变,并且引用初始化时指向的变量的值也会改变,
在C++中还可以定义一个类的对象的引用,与对象共享一块地址,不能定义第一个类的引用,因为类只是一种类型,没有内存地址,引用必须指向一块
内存地址,
- #include <iostream>
- using namespace std;
- class Test
- {
- public:
- void set(int val);
- int Get();
- private:
- int i;
- };
- void Test::set(int val)
- {
- i = val;
- }
- int Test::Get()
- {
- return i;
- }
- int main()
- {
- Test T; //定义类的对象
- Test &rT = T; //定义类的对象的引用
- //Test &rTest = Test //不能这样定义一个类的引用
- T.set(20);
- cout << "对象的引用的rT.Get()值:" << rT.Get() << endl;
- rT.set(40);
- cout << "对象的T.Get()值:" << T.Get() << endl;
- return 1;
- }
#include <iostream>
using namespace std;
class Test
{
public:
void set(int val);
int Get();
private:
int i;
};
void Test::set(int val)
{
i = val;
}
int Test::Get()
{
return i;
}
int main()
{
Test T; //定义类的对象
Test &rT = T; //定义类的对象的引用
//Test &rTest = Test //不能这样定义一个类的引用
T.set(20);
cout << "对象的引用的rT.Get()值:" << rT.Get() << endl;
rT.set(40);
cout << "对象的T.Get()值:" << T.Get() << endl;
return 1;
}
执行的结果:
指针进行删除后一般要把指针指向空,而引用不需要,不管怎么样,引用永远指向初始化的内存空间,就算是指针的引用,指针进行删除
操作后,引用的内存地址还是不变,不过指针删除后内存的数据也被删除,如果对象在栈中,当对象超出作用域后,引用和对象一起消失,
如果对象在堆中,堆的空间必须使用指针访问,因为堆空间一般是手动分配,在分配内存时定义一个指针指向分配的空间,所以堆空间只能
指针访问,没必要用引用,不过可以定义指针引用但如果删除指针后,引用的地址不变,只是内存的数据被删除
引用常见的使用是用于传递函数参数,使用时很好用,参数的传递常见的有按值传递,按地址传递和引用传递,在说引用传递前先看看前面的两种,
1. 按值传递
先看一下例子
看执行的结果,通过set()函数后主函数的值还是不变,这是为什么?因为按值传递,只是把主函数a的值给了set()函数的a值,这两个a的地址不是同一个地址,
在执行的过程中,会把主函数a的地址的数据拷贝给set函数a的地址,通过调式可以看一下这两个a的地址
主函数a的地址:
set()函数a的地址
可以看到是不同的地址
2. 按地址传递
可以看到主函数a的值通过set()函数后已经改变,其实这时候这两a是同一块内存地址,set()函数中的参数a是指针指向主函数a的地址,所以是同一
块内存地址,对set()中a的值修改,主函数中的a的值也改变,因为同那块内存地址的数据改变了;不过set()函数中要使用到指针,比较麻烦而且难使用,
所以就有了引用传递
3. 引用传递
主函数中的a值经过set()函数后一样会发生改变,而且使用起来方便,不像使用指针那样难以管理,这就是使用引用比使用指针的好处
这样的话,只需要在函数参数中添加引用,这样就可以解决无法返回对个值,只需要把要返回的变量作为引用传递就可以改变多个变量的值
引用的传递在类的对象的应用中是相当有用的...
下面是一个视频资料的截屏
说明了按值传递与其他两种传递的不同之处
这里是使用引用容易出错的地方
这是个引用传递对象,在fun()函数中的对象是区部对象,当fun()函数结束后这个对象也不存在了,所以在主函数中的类对象引用接收fun()函数的对象是不存在的,所以输出一个
随机值,那为什么下面这个就能正确输出?
其实这是在fun()函数返回时是使用了按值传递,fun()前没有了&,所以在主函数的引用接收到的fun()函数对象的值,
所以是正确的