1.引用的概念及用法
引用不是定义一个新的变量,而是给一个已经定义的变量重新起一个别名
定义的格式:类型 & 引用变量名 = 已定义过的变量名
引用的特点:
a)一个变量可取多个别名
b)引用必须初始化
c)引用只能在初始化的时候引用一次,不能改变为再引用其他的变量
int& b = a; //为一块已开辟的空间a取名为b(b是a的别名)
int* p = &a; //p指向空间a
int a = 10;
int& b = a; //b是a的别名
int i = 100;
b = i; //单纯将i的值赋给b,b任然是a的别名,而此时a=b=100
const int a = 10;
int& b =a;
显然此时编译器会报错,原因是变量a用const修饰,具有常性,不能被修改。而此时a的别名b类型是int,可被修改,发生冲突,程序编译出错
此时应该将int& b=a;
改为const int& b = a;
。
类似的:
int& c = 20; //这样表示是错误的。常量具有常性,只有常引用可以引用常量
const int& c = 20; //正确表示方法
int d = 10;
float e = d; //存在隐式类型转换
float& f = d; //错误
const float& f = d; //正确
2.引用做参数
void Swap(int& a, int& b)
{
int tmp = a;
a = b;
b = tmp;
}
int main()
{
int a = 10;
int b = 20;
Swap(a, b);
cout << "a=" << a << endl;
cout << "b=" << b << endl;
system("pause");
return 0;
}
结果为:
显然传引用同样可以起到修改实参作用,此时形参是引用类型,形参是实参的别名,并未给形参开辟空间。同样的用传地址的方法传参也可以起到修改实参的作用,但此时需给形参开辟空间。
结论:①引用传参可以减少空间浪费
②引用传参可以提高效率
若实参不想被修改,则可以用const修饰形参
void Func(const Big& big)
{
}
3.引用做返回值
①传值返回
int Add(int a, int b) //传值返回
{
int c = a + b;
return c;
}
int main()
{
int a = 10;
int b = 20;
int ret = Add(a, b);
cout << "ret=" << ret << endl;
return 0;
}
若用int& ret = Add(10,20);
则会发生错误,因为函数返回的是临时变量,具有常性,必须用const修饰,应改为const int& ret = Add(10,20);
。
②传引用返回
int& Add(int a, int b)
{
int c = a + b;
return c;
}
int main()
{
int a = 10;
int b = 20;
int& ret = Add(a, b);
Add(1, 2);
cout << "ret=" << ret << endl;
return 0;
}
结果为ret = 3
4.汇编层看引用的特性
int a = 10;
int& b = a;
语法上b是a的别名(不开辟空间),但底层是通过指针实现的(开辟了空间)。
结论:
1.不要返回一个临时变量的引用。
2.如果返回对象出了当前函数的作用域依旧存在,则最好使用引用返回,因为这样更高效。
5.引用和指针的区别
引用与指针的区别和联系
⑴引用只能在定义时初始化一次,之后不能改变指向其他变量(从一而终);指针变量的值可变。
⑵引用必须指向有效的变量,指针可以为空。
⑶sizeof指针对象和引用对象的意义不一样。sizeof引用得到的是所指向的变量的大小,而sizeof指针是对象地址的大小。
⑷指针和引用自增(++)自减(–)意义不一样。
⑸相对而言,引用比指针更安全。
注:32位系统下指针一定为4个字节
64位系统下与编译器配置有关,工程创建后决定了指针的大小
有关越界的小常识:
越界不一定报错
越界读一般不报错
如: