1. 引用
引用就是给变量起别名。
语法: 数据类型& 别名 = 变量名;
这里别名等价于变量名;
int a = 10;
int &b = a;
// b 等价于 a;
注意:
- 引用必须初始化,不初始化的话你都不知道给谁起别名了。
- 引用一旦初始化就不可以初始化别的变量了(投机取巧的记忆:你见过重复定义的两个变量可以行吗?不可以对吧,那就是不可以了)
eg:引用必须初始化
int &b ; //错误,没有初始化
int a;
int &b = a; //错误 ,a也没有初始化
eg:引用一旦初始化就不可以初始化别的变量了。
int a = 10;
int c = 20;
int &b = a; // 正确
int &b = c; //错误,因为b 引用了 a,就不可以引用别人了。
int &d = a; //正确,虽然a被引用了,可是 d是a另一个别名,相当于a 有两个别名 b 和 d;
//注意假如d修改了,a和 b也会修改了值
2. 引用做函数的形参
作用:函数传参时们可以利用引用让形参修饰实参,也就是说形参就是实参的别名。
优点:可以简化指针修饰实参。
总结:引用做函数参数,可以和地址传值产生同样的效果。
# include<iostream>
using namespace std;
//交换函数
//1.值传递
void MySwap1(int a, int b)
{
int t;
t = a;
a= b;
b = t;
}
//2.地址传递
void MySwap2(int* a, int* b)
{
int t = *a;
*a = *b;
*b = t;
}
//3.引用传递
void MySwap3(int &a, int &b)
{
int t;
t = a;
a = b;
b = t;
}
int main()
{
int a = 10;
int b = 20;
MySwap1(a, b);//值传递,并不会修改实参的数据,修改的是形参的数据,也就是说形参不会修饰实参
//a b值不变
cout << "MySwap1的a = " << a << endl;
cout << "MySwap1的b = " << b << endl;
MySwap2(&a, &b); //地址传递
//a b 值变了
cout << "MySwap2的a = " << a << endl;
cout << "MySwap2的b = " << b << endl;
MySwap3(a, b); // 引用传递
//a b 值变了
cout << "MySwap3的a = " << a << endl;
cout << "MySwap3的b = " << b << endl;
system("pause");
return 0;
}
测试结果
3. 引用做函数的返回值
注意:不要返回局部变量的引用
其实也就是说,出了作用域生命周期会消失的,都不要返回去,这样会野指针,访问非法内存。
int& text1()
{
int a = 10;
return a; //局部变量的形式返回,引用接受的是随机值
}
假如你在vs2013环境下测试的话,它会给你返回10的值,其实这是编译器给你的优化,本质是随机值,要记住,有时候编译器会傻乎乎的给你优化一些结果。
int& text2()
{
static int a = 10; // 静态变量,不是局部变量
return a;
}
返回的值正确 a = 10;
4. 引用的本质
引用的本质是一个指针常量(该指针是一个常量,不可以被修改)。这就解释了为什么引用一旦初始化就不可以被修改的原因了。
# include<iostream>
using namespace std;
int main()
{
int a = 10;
int &ref = a;
//编译器发现是个引用,
//自动转化为 int* const ref = &a;
ref = 100;
// 编译器发现ref是引用
//自动转化为 *ref = 100;
return 0;
}
画个图理解下:
5. 常量引用
使用场景:假如你知道函数的形参不用修改其值的话,就给这个引用加 const;
这样使用的好处很多:
对于调用者来说,他们可以使用传const和非const的参数;
对于设计者来说:他们假如修改了该cosnt修饰的变量,那么编译时候就会有报错结果提示;
//这个函数的目的就是为了打印ref的值,
//并不想修改ref的值
void text1(const int &ref)
{
ref = 100; //错误,有const修饰了,常量引用不可以修改其值;
cout << ref << endl;
}
const引用还可以引用不相同类型的对象
double d = 3.14;
int& a = d; //普通的引用不可以引用不同类型的对象
const int& b = d; //可以编译通过
//上面的语句可以过其实本质是发生了隐式类型转换
即:int tmp = (int)d; const int& b = tmp;
也就是说:const int& b = d; 可以编译通过const有很大作用
6 引用和指针的区别
引用和指针的不同点:
- 引用在定义时必须初始化,指针没有要求
- 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何一个同类型
实体 - 没有NULL引用,但有NULL指针
- 在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32位平台下占
4个字节) - 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小
- 有多级指针,但是没有多级引用
- 访问实体方式不同,指针需要显式解引用,引用编译器自己处理
- 引用比指针使用起来相对更安全