引用(reference)是c++对c语言的重要扩充。引用就是某一已存在变量(目标)的一个别名,对引用的操作与对变量直接操作完全一样。
引用的声明方法:类型标识符 &引用名=目标变量名;
假若有一变量a,想给它起一别名,可以这样写:
int a; //定义a是整形变量
int &b = a; //声明b是a的引用
以上语句声明了b是a的引用,即b是的别名,经过这样声明后,a或b作用相同,代表同一变量。
注意:
const int (&ref)[3] ={2,3,5}; //gcc编译的时候加上选项 -std=c++0x
ref[0] = 35; //错误
void swapint( int*a, int*b)
{
int temp;
temp = *a;
*a = *b;
*b = temp;
}
void swapint( int &a, int &b)
{
int temp;
temp = a;
a = b;
b = temp;
}
const maxCard=100;
Class Set
{
int elems[maxCard];//集合中的元素,maxCard表示集合中元素个数的最大值。
int card;//集合中元素的个数。
public:
Set(){card=0;}//构造函数
friend Setoperator *(Set,Set);//重载运算符号*,用于计算集合的交集用对象作为传值参数
//friendSetoperator*(Set&,Set&)重载运算符号*,用于计算集合的交集用对象的引用作为传值参数
...
}
void Test
{
int a ;
const int &ra=a;
ra=1; //错误,const修饰不可改
a=1; //正确
}
string foo( ); void bar(string & s); 那么下面的表达式将是非法的: bar(foo( )); bar("hello world"); //原因在于foo( )和"hello world"串都会产生一个临时对象,而在C++中,这些临时对象都是const类型的。因此上面的表达式就是试图将一个const类型的对象转换为非const类型,这是非法的。 引用型参数应该在能被定义为const的情况下,尽量定义为const 。
#include <iostream>
using namespace std;
int& fun(int& a)
{
a++;
return a;
} //把a返回引用函数,也就是说这个fun()就是a的别名
int main()
{
int b =10;
fun(b); //同理,fun(b)就是b自增后的b的别名
cout << b <<endl;
return 0;
}
【例】:
void Test
{
const int a = 10;
int &b = a; //错误。如果引用成功,可通过a修改成功,而原题是const修饰b,是不可修改的。
const int &b = a; // 正确
const int &c = 10; //正确,表示10不可修改
}
【例】:
void Test
{
double a = 10.34;
const int &b = a; //正确,
a = 23.13;
}
// b = 12;
//如果b是a得引用(两者类型相同),则两者使用同一空间,但事实上b并不是a得引用,因为两者有不同的空间,借助一段未命名空间过度,临时变量有常性,所以要加上const修饰。
【例】:数组引用
void Test
{
int a[10];
int (&ra) [10] = a;
int (&ra) [9] = a; // 错误,两者类型相同,不可引用
a [0] = 10;
ra[1] = 20;
}
FunTest(&a)
{
int a = 10;
return a;
}
保证返回值生命周期比函数生命周期长
int & FunTest()
{
int ret = 10;
return ret;
}
int main()
{
int &r = FunTest();
printf("%d\n", r);
printf("%d\n", r);
}
// 10
随机值 //第一次调用时,回来就销毁ret, 重新创建栈帧, 第二次打印出随机值
引用和多态
1.指针和引用的定义和性质区别:
(1)指针:指针是一个变量,只不过这个变量存储的是一个地址,指向内存的一个存储单元;而引用跟原来的变量实质上是同一个东西,只不过是原变量的一个别名而已。如:
int a=1;int *p=&a;//定义了一个整形变量和一个指针变量p,p的值是a存储单元的地址。
int a=1;int &b=a;//定义了一个整形变量a和这个整形a的引用b,事实上a和b是同一个东西,在内存占有同一个存储单元。
(2)指针可以有多级,但是引用只能是一级(int **p;合法 而 int &&a是不合法的)
(3)指针的值可以为空,但是引用的值不能为NULL,并且引用在定义的时候必须初始化;
(4)指针的值在初始化后可以改变,即指向其它的存储单元,而引用在进行初始化后就不会再改变了。
(5)"sizeof引用"得到的是所指向的变量(对象)的大小,而"sizeof指针"得到的是指针本身的大小;
(6)指针和引用的自增(++)运算意义不一样;
2.指针和引用作为函数参数进行传递时的区别:
(1)指针作为参数进行传递:
#include<iostream>
using namespace std;
void swap(int *a,int *b)
{
int temp=*a;
*a=*b;
*b=temp;
}
int main(void)
{
int a=1,b=2;
swap(&a,&b);
cout<<a<<" "<<b<<endl;
system("pause");
return 0;
}
结果为2 1;
用指针传递参数,可以实现对实参进行改变的目的,是因为传递过来的是实参的地址,因此使用*a实际上是取存储实参的内存单元里的数据,即是对实参进行改变,因此可以达到目的。
再看一个程序:
#include<iostream>
using namespace std;
void test(int *p)
{
int a=1;
p=&a;
cout<<p<<" "<<*p<<endl;
}
int main(void)
{
int *p=NULL;
test(p);
if(p==NULL)
cout<<"指针p为NULL"<<endl;
return 0;
}
运行结果为:
0x22ff44 1
指针p为NULL
大家可能会感到奇怪,怎么回事,不是传递的是地址么,怎么p会是NULL?事实上,在main函数中声明了一个指针p,并赋值为NULL,当调用test函数时,事实上传递的也是地址,只不过传递的是指地址。也就是说将指针作为参数进行传递时,事实上也是值传递,只不过传递的是地址。当把指针作为参数进行传递时,也是将实参的一个拷贝传递给形参,即上面程序main函数中的p何test函数中使用的p不是同一个变量,存储2个变量p的单元也不相同(只是2个p指向同一个存储单元),那么在test函数中对p进行修改,并不会影响到main函数中的p的值。
如果要想达到也同时修改的目的的话,就得使用引用了。
2.将引用作为函数的参数进行传递。
在讲引用作为函数参数进行传递时,实质上传递的是实参本身,即传递进来的不是实参的一个拷贝,因此对形参的修改其实是对实参的修改,所以在用引用进行参数传递时,不仅节约时间,而且可以节约空间。
看下面这个程序:
#include<iostream>
using namespace std;
void test(int &a)
{
cout<<&a<<" "<<a<<endl;
}
int main(void)
{
int a=1;
cout<<&a<<" "<<a<<endl;
test(a);
system("pause");
return 0;
}
输出结果为: 0x22ff44 1
0x22ff44 1
再看下这个程序:
这足以说明用引用进行参数传递时,事实上传递的是实参本身,而不是拷贝。
所以在上述要达到同时修改指针的目的的话,就得使用引用了。
#include<iostream>
using namespace std;
void test(int *&p)
{
int a=1;
p=&a;
cout<<p<<" "<<*p<<endl;
}
int main(void)
{
int *p=NULL;
test(p);
if(p!=NULL)
cout<<"指针p不为NULL"<<endl;
system("pause");
return 0;
}
输出结果为:0x22ff44 1
指针p不为NULL