分类: C/C++
2011-04-30 09:43:07
引用的概念
引用是个别名,当建立引用时,程序用另一个变量或对象(目标)的名字初始化它。从那时起,引用作为目标的别名而使用,对引用的改动实际就是对目标的改动。
为建立引用,先写上目标的类型,后跟引用运算符“&”, 然后是引用的名字。引用能使 用任何合法变量名。
例如,引用一个整型变量:
int someInt;
int& rInt=someInt;
声明rInt是对整数的引用,初始化为引用someInt。在这里,要求someInt已经有声明或定义,而引用仅仅是它的别名,不能喧宾夺主。
引用不是值,不占存储空间,声明引用时,目标的存储状态不会改变。所以,既然定义的概念有具体分配空间的含义,那么引用只有声明,没有定义。
例如,下面的程序建立和使用引用:
//*********************
//** ch9_1.cpp **
//*********************
#include
void main()
{
int intOne;
int& rInt=intOne;
intOne=5; cout <<"intOne:" < 运行结果为: 引用的操作 如果程序寻找引用的地址,它只能找到所引用的目标的地址。 //********************* #include void main() int One=5; cout <<"&intOne:" <<&intOne < 运行结果为: 引用一旦初始化,它就维系在一定的目标上,再也不分开。任何对该引用的赋值,都是对引用所维系的目标赋值,而不是将引用维系到另一个目标上。 #include void main() intOne=5; cout <<"&intOne:" <<&intOne < int intTwo=8; cout <<"&intOne:" <<&intOne < 运行结果为: rInt=intTwo; 等价于 intone=intTwo; 什么能被引用 若一个变量声明为T&,即引用时,它必须用T类型的变量或对象, 或能够转换成T类型的对象进行初始化。 http://hi.baidu.com/bellgrade/blog/item/79a0a412575e61dcf7039eb7.html
cout <<"intOne:" <
int one:5
rInt:5
intOne:7
rInt:7
引用rInt用intOne来初始化。以后,无论改变intOne还是rInt,实际都是指intOne,两者的值都一样。
引用在声明时必须被初始化,否则会产生编译错误。
->引用运算符与地址操作符使用相同的符号。尽管它们显然是彼此相关的,但它们不一样。
引用运算符只在声明的时候使用,它放在类型名后面,例如:
int& rInt=intOne;
任何其他“&”的使用都是地址操作符,例如:
int* ip=&intOne;
cout<<&ip;
->与指针类似,下面三种声明引用的方法都是合法的:
int& rint;
int &rInt;
int & rInt;
下面的语句包含一个引用的声明和一个变量的定义:
int& rInt,sa; //会误以为声明了两个引用
为了提高可读性,不应在同一行上同时声明引用、指针和变量。
例如,下面的程序取引用的地址:
//** ch9_2.cpp **
//*********************
{
int intOne;
int& rInt=intOne;
cout <<"intOne:" <
intOne:5
rInt:5
&intOne:00F3:5300 .
&rInt:00F3:5300
C++没有提供访问引用本身地址的方法, 因为它与指针或其他变量的地址不同,它没有任何意义。引用在建立时就初始化,而且总是作为目标的别名使用,即使在应用地址操作符时也是如此。对引用的理解可以见图9-1。
图9-1 定义rht引用与变量的关系
例如,下面的程序给引用赋新值:
//*********************
//** ch9_3.cpp **
//*********************
{
int intOne;
int& rInt=intOne;
cout <<"intOne:" <
rInt=intTwo;
cout <<"intOne:" <
intOne:5
rInt:5
&intOne:0110:F150
&rInt:0110:F150
intOne:8
intTwo:8
rInt:8
&intOne:0110:F150
&intTwo:0110:F14E
&rInt:0110:F150
在程序中,引用rInt被重新赋值为变量intTwo。从运行结果看出,rInt仍然维系在原intOne上,因为rInt与LntOne的地址是一样的,见图9-2。
图9—2 引用被赋值的意义
引用与指针有很大的差别,指针是个变量,可以把它再赋值成指向别处的地址,然而,建立引用时必须进行初始化并且决不会再关联其他不同的变量。
如果引用类型T的初始值不是一个左值,那么将建立一个T类型的目标并用初始值初始化,那个目标的地址变成引用的值。
例如,下面的代码是合法的:
double& rr=1;
在这种情况下:
(1)首先作必要的类型转换;
(2)然后将结果置于临时变量;
(3)最后,把临时变量的地址作为初始化的值。
所以上面的语句解释为:
double temp;
temp=double(1);
double& rr=temp;
上面的语句中将临时变量显式地表示出来,事实上,临时变量并不在存放局部变量的栈区。由于指针也是变量,所以可以有指针变量的引用:
int * a;
int* &p=a; //表示int*的引用p初始化为a
int b=8;
p=&b; //ok! p是a的别名,是一个指针
指针变量的引用,见图9-3。
对void进行引用是不允许的。例如:
void& a=3; //error
void只是在语法上相当于一个类型,本质上不是类型,但是没有任何一个变量或对象,其类型为void。
不能建立引用的数组:
int a[10];
int& ra[10]=a; //error
因为数组是某个数据类型元素的集合,数组名表示该元素集合空间的起始地址,它自己不是一个名副其实的数据类型。
引用本身不是一种数据类型,所以没有引用的引用,也没有引用的指针。例如:
int a;
int& ra=a;
int& *p=&ra; //error企图定义一个引用的指针
引用不是类型, 定义引用在概念上不产生内存空间, 所以,在引用之上的引用不存在,而且,引用的指针指向谁呢?
引用不能用类型来初始化:
int& ra=int; //error
因为引用是变量或对象的引用,而不是类型的引用。
有空指针,无空引用。不应有下面的引用声明,否则会有运行错误:
int& ri=NULL; //毫无意义