zoukankan      html  css  js  c++  java
  • 关于"引用"的几点说明

    一、引用的基本知识

    引用就是某一变量(目标)的一个别名,对引用的操作与对变量直接操作完全一样。引用的声明方法:类型标识符 &引用名=目标变量名; 说明:

    (1)&在此不是求地址运算,而是起标识作用。

    (2)类型标识符是指目标变量的类型。

    (3)声明引用时,必须同时对其进行初始化。

    (4)引用声明完毕后,相当于目标变量名有两个名称,即该目标原名称和引用名,且不能再把该引用名作为其他变量名的别名。

        int a,&ra=a;a为目标原名称,ra为目标引用名。给ra赋值:ra=1; 等价于 a=1;

    (5)声明一个引用,不是新定义了一个变量,它只表示该引用名是目标变量名的一个别名,它本身不是一种数据类型,因此引用本身不占存储单元,系统也不给引用分配存储单元。故:对引用求地址,就是对目标变量求地址。&ra与a相等。

    (6)不能建立数组的引用。因为数组是一个由若干个元素所组成的集合,所以无法建立一个数组的别名。

    例如: Point pt1(10,10);

    Point &pt2=pt1; 定义了pt2为pt1的引用。通过这样的定义,pt1和pt2表示同一对象。

    需要特别强调的是引用并不产生对象的副本,仅仅是对象的同义词。因此,当下面的语句执行后:

    pt1.offset(12,12);

    pt1和pt2都具有(12,12)的值。

    引用必须在定义时马上被初始化,因为它必须是某个东西的同义词。你不能先定义一个引用后才

    初始化它。例如下面语句是非法的:

    Point &pt3;

    pt3=pt1;

    那么既然引用只是某个东西的同义词,它有什么用途呢?

    下面讨论引用的两个主要用途:作为函数参数以及从函数中返回左值。

    二、引用作为函数参数

    1、传递可变参数

    传统的c中,函数在调用时参数是通过值来传递的,这就是说函数的参数不具备返回值的能力。

    所以在传统的c中,如果需要函数的参数具有返回值的能力,往往是通过指针来实现的。比如,实现

    两整数变量值交换的c程序如下:

    void swapint(int *a,int *b)

    {

      int temp;

      temp=*a;

      *a=*b;

      *b=temp;

    }

    使用引用机制后,以上程序的c++版本为:

    void swapint(int &a,int &b)

    {

      int temp;

      temp=a;

      a=b;

      b=temp;

    }

    调用该函数的c++方法为:swapint(x,y); c++自动把x,y的地址作为参数传递给swapint函数。

    2、给函数传递大型对象

    当大型对象被传递给函数时,使用引用参数可使参数传递效率得到提高,因为引用并不产生对象的

    副本,也就是参数传递时,对象无须复制。下面的例子定义了一个有限整数集合的类:

    const maxCard=100;

    Class Set

    {

      int elems[maxCard]; // 集和中的元素,maxCard 表示集合中元素个数的最大值。

      int card; // 集合中元素的个数。

    public:

      Set () {card=0;} //构造函数

      friend Set operator * (Set ,Set ) ; //重载运算符号*,用于计算集合的交集 用对象作为传值参数

      // friend Set operator * (Set & ,Set & ) 重载运算符号*,用于计算集合的交集用对象的引用作为传值参数

      ...

    }

    先考虑集合交集的实现

    Set operator *( Set Set1,Set Set2)

    {

      Set res;

      for(int i=0;i<Set1.card;++i)

        for(int j=0;j>Set2.card;++j)

          if(Set1.elems==Set2.elems[j])

          {

            res.elems[res.card++]=Set1.elems;

            break;

          }

      return res;

    }

    由于重载运算符不能对指针单独操作,我们必须把运算数声明为 Set 类型而不是 Set * 。

    每次使用*做交集运算时,整个集合都被复制,这样效率很低。我们可以用引用来避免这种情况。

    Set operator *( Set &Set1,Set &Set2)

    {

      Set res;

      for(int i=0;i<Set1.card;++i)

      {

          for(int j=0;j>Set2.card;++j)

            if(Set1.elems==Set2.elems[j])

            {

              res.elems[res.card++]=Set1.elems;

              break;

            }

      }

      return res;

    }

    三、引用作为返回值

      如果一个函数返回了引用,那么该函数的调用也可以被赋值。这里有一函数,它拥有两个引用参数并返回一个双精度数的引用:

      double &max(double &d1,double &d2)

      {

        return d1>d2?d1:d2;

      }

      由于max()函数返回一个对双精度数的引用,那么我们就可以用max() 来对其中较大的双精度数加1:

    max(x,y)+=1.0;

    四、常引用

      常引用声明方式:const 类型标识符&引用名=目标变量名;

      用这种方式声明的引用,不能通过引用对目标变量的值进行修改,从而使引用的目标成为const,达到了引用的安全性。

    【例】:

      int a ;

      const int &ra=a;

      ra=1; //错误

      a=1; //正确

      这不光是让代码更健壮,也有些其它方面的需要。

    【例】:假设有如下函数声明:

      string foo( );

      void bar(string & s);

      那么下面的表达式将是非法的:

      bar(foo( ));

      bar("hello world");

      原因在于foo( )和"hello world"串都会产生一个临时对象,而在C++中,这些临时对象都是const类型的。因此上面的表达式就是试图将一个const类型的对象转换为非const类型,这是非法的。

      引用型参数应该在能被定义为const的情况下,尽量定义为const 。

    五、引用和多态

    引用是除指针外另一个可以产生多态效果的手段。这意味着,一个基类的引用可以指向它的派生类实例。

    【例】:

    class A;

    class B:public A{……};

    B b;

    A &Ref = b; // 用派生类对象初始化基类对象的引用

    Ref 只能用来访问派生类对象中从基类继承下来的成员,是基类引用指向派生类。如果A类中定义有虚函数,并且在B类中重写了这个虚函数,就可以通过Ref产生多态效果。

     

  • 相关阅读:
    大数加法、乘法实现的简单版本
    hdu 4027 Can you answer these queries?
    zoj 1610 Count the Colors
    2018 徐州赛区网赛 G. Trace
    1495 中国好区间 尺取法
    LA 3938 动态最大连续区间 线段树
    51nod 1275 连续子段的差异
    caioj 1172 poj 2823 单调队列过渡题
    数据结构和算法题
    一个通用分页类
  • 原文地址:https://www.cnblogs.com/hoobey/p/5247408.html
Copyright © 2011-2022 走看看