* const
。const int &e ; //相当于const int *const e;
,相当于是指向常量的指针常量,既不能修改其值,也不能修改指向的内存空间。另外,普通引用相当于int *const e1;
。int a = 3;int &ra = a;
int b = 4;ra = b; //相当于把B的值赋给ra,并不是引用新的对象。
cout << a << ' ' << ra << ' ' << b << endl; // 4 4 4
b = 5;
cout << a << ' ' << ra << ' ' << b << endl; // 4 4 5
a = 6;
cout << a << ' ' << ra << ' ' << b << endl; // 6 6 5
//下面为什么没有编译报错,奇怪;
struct Student{
int &a;
};
void swap(int &p1, int &p2) {
//此处函数的形参p1, p2都是引用;
int p;
p=p1;
p1=p2;
p2=p;
}
1)传递引用与传递指针的效果一样。这时被调函数的形参就成为原来主调函数中的实参对象的一个别名,所以在被调函数中对形参的操作就是对其相应的实参的操作。
2)使用引用传递函数的参数,在内存中并没有产生实参的副本,它是直接对实参操作;而使用一般变量传递函数的参数,当发生函数调用时,需要给形参分配存储单元,形参是实参的副本。如果传递的是对象,还将调用拷贝构造函数。因此,当参数传递的数据较大时,用引用比用一般变量传递参数的效率和所占空间都好。
3)使用指针形参虽然也能达到引用形参的效果,但是在被调函数中同样要给形参分配内存空间,且需要使用*指针变量名
的形式进行运算,这很容易产生错误且程序的阅读性较差;另一方面,在主调函数的调用点处,必须用变量的地址作为实参。而引用更容易使用,更清晰。
4)如果既要利用引用提高程序的效率,又要保护传递给函数的数据不在函数中被改变,就应使用const引用。
5)使用引用形参返回额外信息。第一种方法,使用自定义类型,让它包含我们需要的成员;第二种方法,可以给函数传入更多的引用形参来达到效果。
类型标识符 &函数名(形参列表){ 函数体 }
。#include
using namespace std;
int temp; //定义全局变量temp
int fun1(int x){
//以返回值的方法返回函数值
temp=x*x;
return temp;
}
int &fun2(int x){
//以引用方式返回函数值
temp=x*x;
return temp;
}
int main()
{
int a = fun1(10);
//返回全局变量temp的值时,C++会在内存中创 建临时变量并将temp的值拷贝给临时变量。
//当返回到主函数main后,赋值语句a=fun(10)会把临时变量的值再拷贝给变量a。
int &b = fun1(10);//编译错误;
//返回时,首先拷贝temp的值给临时变量;
//返回到主函数后,用临时变量来初始化引用变量b,使得b成为该临时变量到的别名。
//由于临时变量的作用域短暂;
//在C++标准中,临时变量或对象的生命周期在一个完整的语句表达式结束后便宣告结束,也就是在语句int &b=fun1(10);之后;
//所以b面临无效的危险,很有可能以后的值是个无法确定的值,因此编译错误。
//如果真的希望用函数的返回值来初始化一个引用,应当先创建一个变量;
//将函数的返回值赋给这个变量,然后再用该变量来初始化引用;
int c=fun2(10);
//函数fun2()的返回值不产生副本,而是直接将变量temp返回给主函数。
//即主函数的赋值语句中的值是直接从变量temp中拷贝而来,
//(也就是说c只是变量temp的一个拷贝而非别名)这样就避免了临时变量的产生。
//尤其当变量temp是一个用户自定义的类的对象时,
//这样就避免了调用类中的拷贝构造函数在内存中创建临时对象的过程,
//提高了程序的时间和空间的使用效率。
int &d=fun2(10);
//函数fun2()的返回值不产生副本,而是直接将变量temp返回给主函数
//在主函数中,一个引用声明d用该返回值初始化,也就是说此时d成为变量temp的别名。
//由于temp是全局变量,所以在d的有效期内temp始终保持有效,故这种做法是安全的。
return 0;
}
1)不能返回局部变量的引用。如果使用局部变量的引用,那么局部变量会在函数返回后被销毁,此时对temp的引用就会成为没有指向的引用,也就是引用非法内存,因此编译错误。
2)不能返回函数内部通过new分配的内存的引用。虽然不存在局部变量的被动销毁问题,但如果返回函数的引用只是作为一个临时变量出现,而没有将其赋值给一个实际的变量,那么就可能造成这个引用所指向的空间无法释放的情况(由于没有具体的变量名,故无法用delete手动释放内存),从而造成内存泄漏。因此应当避免这种情况的发生。
3)当返回类成员的引用时最好是const引用,这样可以避免在无意的情况下破坏该类的成员。
4)可以用函数返回的引用作为赋值表达式中的左值。
5)当函数返回值为引用时,若返回栈变量,不能成为其它引用的初始值,不能作为左值使用;若返回静态全局变量,可以成为其他引用的初始值即可作为左值使用,也可作为右值使用。
const 类型标识符 &引用名=目标变量名;
,用这种方式声明的引用,不能对const引用的值进行修改,从而达到引用的安全性。换句话说,const引用仅仅对引用本身可参与的操作做出限定,没有对引用的对象做限定。因为如果引用的对象可能是一个非const,允许通过其它途径来改变它的值。例如:int a=2;
const int &ra=a; //正确,允许const引用绑定到非const的对象;
ra=1; //错误,不能通过const引用对目标变量值进行修改;
a=1; //正确;
int &n=10; //编译报错;
const int &n = 10; //正确,const引用可以绑定非const引用、字面值等等;
//编译器处理:int tmp=10; const int& y=tmp;
string foo();
void bar(string &s);
bar(foo()); //非法;
bar("hello world"