Chinaunix首页 | 论坛 | 博客
  • 博客访问: 240288
  • 博文数量: 38
  • 博客积分: 710
  • 博客等级: 上士
  • 技术积分: 315
  • 用 户 组: 普通用户
  • 注册时间: 2010-11-06 10:52
文章分类

全部博文(38)

文章存档

2016年(1)

2015年(10)

2014年(1)

2013年(7)

2011年(9)

2010年(10)

我的朋友

分类: 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:" <      cout <<"rInt:" <

      cout <<"intOne:" <      cout <<"rInt:" <    }

  运行结果为:
    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  **
    //*********************

    #include

    void main()
    {
     int intOne;
     int& rInt=intOne;

     int One=5;
     cout <<"intOne:" <     cout <<"rInt:" <

     cout <<"&intOne:" <<&intOne <     cout <<"&rInt:" <<&rInt <    }

  运行结果为:
    intOne:5
    rInt:5
    &intOne:00F3:5300 .
    &rInt:00F3:5300

  C++没有提供访问引用本身地址的方法, 因为它与指针或其他变量的地址不同,它没有任何意义。引用在建立时就初始化,而且总是作为目标的别名使用,即使在应用地址操作符时也是如此。对引用的理解可以见图9-1。


图9-1 定义rht引用与变量的关系

  引用一旦初始化,它就维系在一定的目标上,再也不分开。任何对该引用的赋值,都是对引用所维系的目标赋值,而不是将引用维系到另一个目标上。
例如,下面的程序给引用赋新值:
    //*********************
    //**   ch9_3.cpp  **
    //*********************

    #include

    void main()
    {
     int intOne;
     int& rInt=intOne;

     intOne=5;
     cout <<"intOne:" <     cout <<"rInt:" <

     cout <<"&intOne:" <<&intOne <     cout <<"&rInt:" <<&rInt <

     int intTwo=8;
     rInt=intTwo;
     cout <<"intOne:" <     cout <<"intTwo:" <     cout <<"rInt:" <

     cout <<"&intOne:" <<&intOne <     cout <<"&intTwo:" <<&intTwo <     cout <<"&rInt:" <<&rInt <    }

  运行结果为:
    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 引用被赋值的意义

  rInt=intTwo; 等价于 intone=intTwo;
  引用与指针有很大的差别,指针是个变量,可以把它再赋值成指向别处的地址,然而,建立引用时必须进行初始化并且决不会再关联其他不同的变量。

什么能被引用

  若一个变量声明为T&,即引用时,它必须用T类型的变量或对象, 或能够转换成T类型的对象进行初始化。
  如果引用类型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; //毫无意义

http://hi.baidu.com/bellgrade/blog/item/79a0a412575e61dcf7039eb7.html

阅读(1376) | 评论(0) | 转发(0) |
0

上一篇:const

下一篇:linux 中errno的使用

给主人留下些什么吧!~~