引用
一、什么是引用
引用不是定义一个新的变量,而是给一个已经定义的变量起一个新的别名。
引用定义的格式为 :
类型&引用变量名=已定义过的变量名
引用的特点是:
①一个引用可起多个别名;
②引用必须进行初始化;
int main()
{
int a=10;
int& c;
}
上述的错误代码,会发生如下的错误:
③引用只能在初始化的时候引用一次,不能再引用其他的变量。
引用举例
int main()
{
int a=10;
int b = 10;
int& c=a;
int&c = b;
}
如果是上述代码就会出现如下问题:
#include <iostream>
using namespace std;
int main()
{
int a = 10;
int& c = a;
cout<<a<<endl;
cout << c << endl;
cout << &a << endl;
cout << &c << endl;
return 0;
}
生成的结果是:a和c的内容是一样的,a和c的地址也是一样的,也就是说c就是a的一个别名;
二、const引用
int main()
{
int a=10;
const int& c=a;
a = 12;//a改变c的值也会随之改变
//c = 1;//不能给常量赋值
const int d = 4;
//int&n = d;//常量具有长性,只有长引用可以引用常量
const int h = d;
double i = 5;
//int& g = i;//i是double类型的,g是int类型的,i赋值给g时要生成一个临时变量,也就是说g引用的是带有常性的临时变量,所以不能赋值
const int&g = i;
cout << a << endl;
cout << c << endl;
return 0;
}
三、引用做返回值和引用传参
①引用传参
解释:x和y都是实参的引用,不需要经过值传递机制,没有了传值和生成副本的时间,这也就提高了程序的效率。
#include <iostream>
using namespace std;
void swap(int& x, int& y)//形参是实参的别名,改变形参的值就是改变了形参
{
int tmp = x;
x = y;
y = tmp;
}
int main()
{
int a = 10;
int b = 20;
swap(a, b);
cout << a << endl;
cout << b << endl;
return 0;
}
②引用做返回值
*以引用返回函数值,定义函数时需要在函数名前加&
*用引用返回一个函数值的最大好处是,在内存中不产生被返回值的副本。
*返回的对象出了当前的作用域依然存在,最好用引用返回,提高了效率。
1》作为全局变量返回
int ret;//注意ret是个全局变量
int Add1(int x,int y)//返回的是ret的地址
{
ret = x + y;
return ret;
}
int& Add2(int x,int y)
{
ret = x + y;
return ret;
}
int main()
{
int a = 2;
int b = 3;
①int m = Add1(a, b);
//这种方式是最常用的传参方式,返回全局变量ret的值时,C++会创建一个临时变量,并将这个值赋值给临时变量,返回到主函数的时候,把这个临时变量的值赋值给m;
②int &m=Add1(a, b);
//这种值传递的方式是有问题的。C++返回的是一个临时变量,而初始化引用m的时候用了临时变量,而临时变量出了作用域会无效,则m就会出现无效的危险。
③int m=Add2(a,b);
//这种的方式是最为高效的,函数在计算出ret这个值的时候,C++并不会创建临时变量来发回它,而是直接返回,现在用一个变量的值来接受它,这种方式带来了程序的执行效率。
④int& m=Add(a,b);
//这种方式也是比较安全的,函数不创建变量来返回它。而是用了一个引用复制它返回,在主函数中,用了它来给一个引用来赋值,它不是临时变量,所以是安全的。
cout << ret << endl;
return 0;
}
2》如果是局部变量
int& Add(int x,int y)
{
int ret;//这里的ret是一个局部变量
ret = x + y;
return ret;
}
int main()
{
int& m = Add(4, 5);
printf("%d\n",m);
return 0;
}//这时候会出现警告, warning C4172: 返回局部变量或临时变量的地址
引用返回时,是取ret的地址到exa寄存器中,不要返回一个临时变量的引用。如果返回对象出了当前的作用域依旧存在时,最好用引用返回,因为这样更高效。
四、指针和引用的对比
1>引用只能在初始化时定义一次(专一性),之后不能改变指向它的指向,而指针变量的指向一直可以改变(之后可以改变它的指向)。
2> 引用必须初始化,但是指针可以初始化,也可以不初始化。
3>sizeof对于指针来说是地址的大小(4字节),但是对于引用来说是它所指向的变量的对应的类型的大小。
double b = 5;
int *p;
cout << sizeof(b) << endl;//输出的结果是8
cout << sizeof(p) << endl;//输出的结果是4
4>指针++:是对它所指向的变量的地址进行++;而引用++:是对初始化它的变量的值进行++;
int b = 5;
int a = 4;
int *p=&a;
b++;
p++;
cout << b << endl;
cout << p << endl;
结果显示的是:
5>引用不创建空间;(它只是给已有的变量取了个别名)
6>引用相对于指针比较安全;不存在空引用,并且引用一旦被初始化为指向一个对象,它就不能被改变为另一个对象的引用,显得很安全。
const 指针仍然存在空指针,并且有可能产生野指针。