一、引用的基本知识

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

(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产生多态效果。

关于"引用"的几点说明的更多相关文章

  1. 【.net 深呼吸】序列化中的“引用保留”

    假设 K 类中有两个属性/字段的类型相同,并且它们引用的是同一个对象实例,在序列化的默认处理中,会为每个引用单独生成数据. 看看下面两个类. [DataContract] public class 帅 ...

  2. CSS 选择器及各样式引用方式

    Css :层叠样式表 (Cascading Style Sheets),定义了如何显示HTML元素. 目录 1. 选择器的分类:介绍ID.class.元素名称.符合.层次.伪类.属性选择器. 2. 样 ...

  3. Android性能优化之巧用软引用与弱引用优化内存使用

    前言: 从事Android开发的同学都知道移动设备的内存使用是非常敏感的话题,今天我们来看下如何使用软引用与弱引用来优化内存使用.下面来理解几个概念. 1.StrongReference(强引用) 强 ...

  4. C++中的引用

    一,C++中引用的基础知识 1.引用的基本概念 1.所谓的引用其实就是对变量起“别名”.引用和变量对应得是相同的内存,修改引用的值,变量的值也会改变,和指针类似. 2.引用在定义的时候必须要初始化,初 ...

  5. Java 为值传递而不是引用传递

    ——reference Java is Pass by Value and Not Pass by Reference 其实这个问题是一个非常初级的问题,相关的概念初学者早已掌握,但是时间长了还是容易 ...

  6. EC笔记:第4部分:21、必须返回对象时,别返回引用

    使用应用可以大幅减少构造函数与析构函数的调用次数,但是引用不可以滥用. 如下: struct St { int a; }; St &func(){ St t; return t; } 在返回t ...

  7. EC笔记:第4部分:20、传递引用代替传值

    考虑以下场景: #include <iostream> #include <string> using namespace std; struct Person { strin ...

  8. 编译器开发系列--Ocelot语言2.变量引用的消解

    "变量引用的消解"是指确定具体指向哪个变量.例如变量"i"可能是全局变量i,也可能是静态变量i,还可能是局部变量i.通过这个过程来消除这样的不确定性,确定所引用 ...

  9. C++右值引用浅析

    一直想试着把自己理解和学习到的右值引用相关的技术细节整理并分享出来,希望能够对感兴趣的朋友提供帮助. 右值引用是C++11标准中新增的一个特性.右值引用允许程序员可以忽略逻辑上不需要的拷贝:而且还可以 ...

  10. 深入理解Java 8 Lambda(语言篇——lambda,方法引用,目标类型和默认方法)

    作者:Lucida 微博:@peng_gong 豆瓣:@figure9 原文链接:http://zh.lucida.me/blog/java-8-lambdas-insideout-language- ...

随机推荐

  1. Android 5.0 源代码结构

    本节书摘来自异步社区<深入理解Android 5 源代码>一书中的第2章,第2.2节分析Android源代码结构,作者 李骏. 网址:https://yq.aliyun.com/artic ...

  2. FolderSync文件夹同步

    FolderSync是一款支持各大国外网盘同步的软件,目前支持 SkyDrive, Dropbox, SugarSync, Ubuntu One, Box.net, LiveDrive, HiDriv ...

  3. ATMEL精妙的IRQ中断处理过程

    A: 从栈地址开始,栈顶为AT91SAM7S64的16K片内RAM尽头0x00204000IRQ_STACK_SIZE = 3*8*4FIQ_STACK_SIZE = 0x004ABT_STACK_S ...

  4. Latest SQLite binary for January 2015

    Latest SQLite binary for January 2015 Well I went through quite a few threads to find an updated, de ...

  5. Visual Studio中Debug和Release的区别

    在Visual Studio中,生成应用程序的时候有2种模式:Debug和Release.两者之间如何取舍呢? 假设有这么简单的一段代码,在主程序中调用方法M1,M1方法调用M2方法,M2方法调用M3 ...

  6. iOS appStore中的应用 实现升级功能

    .h文件中 <UIAlertViewDelegate> .m文件中 #import "SBJson.h"        //解析sbjson 数据 - (void)vi ...

  7. 值得借鉴的Objective-C编程规范

    Daniel's Objective-C Coding Style Guidelines http://google-styleguide.googlecode.com/svn/trunk/objcg ...

  8. 转: Go -- 单例

    最近在学习Golang,想着可以就以前的知识做一些串通,加上了解到go语言也是面向对象编程语言之后.在最近的开发过程中,我碰到一个问题,要用go语言实现单例模式.本着“天下知识,同根同源”(我瞎掰的~ ...

  9. Servlet监听器统计在线人数

    监听器的作用是监听Web容器的有效事件,它由Servlet容器管理,利用Listener接口监听某个执行程序,并根据该程序的需求做出适应的响应. 例1 应用Servlet监听器统计在线人数. (1)创 ...

  10. Objective-C:NSDectionary字典的常见操作

    NSDectionary字典:它是一个存储键值的容器,每一个键key都对应着一个值value,可以通过键key一次性找到目标值value,这是一个比较好的存储器,相比于数组而言,它明显提高了查询效率. ...