一、引用的基本知识

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

(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. Linux rescue

    适用场景: 当误操作修改系统启动文件/etc/fstab, /etc/rc.d/rc.sysinit时,就会造成系统启动时读取磁盘或初始化环境失败,导致linux无法正常启动,此时就可以借助Linux ...

  2. 如何在ubuntu安装phpstorm

    第一步:使用组合键ctrl+alt+t 打开Terminal,cd /home/xxx(当前登录用户名)/downloads(下载目录) 第二步:下载 phpstorm 附截止发文最新版本链接:htt ...

  3. qt 4.8.5 vxworks 6.8 demo

    2692407267@qq.com 环境vxworks 6.8.3 +  GNU Patch.Qt-commercial-4.8.5 0 先安装vxworks 6.8.安装mingw 1 先编wind ...

  4. C++空类产生哪些成员函数 || C++类可以自动生成的6个成员函数

    class Empty {     public:     Empty(); // 缺省构造函数     Empty( const Empty& ); // 拷贝构造函数     ~Empty ...

  5. Quartz Job执行后再更新Job的时间表达式....

    CronTrigger 表达式最大循环时间是1年?那么实际应用中的提醒超过1年怎么办呢? 先看一下界面: 参数说明:提前提醒时间:1-60分钟.1-24小时.1-90天:重复提醒:每1-59分钟.每1 ...

  6. RuntimeError: Working outside of application context.

    flask执行错误: 问题:RuntimeError: Working outside of application context. 方法: from flask import Flask, cur ...

  7. 版本号控制-git(二)

    上次文章给大家介绍了Git的一些基本知识(http://www.cnblogs.com/jerehedu/p/4582398.html).并介绍了使用git init初始化化版本号库.使用git ad ...

  8. 第二章 mybatis使用注解实现in查询(mysql)

    mybatis实现in查询,两种方法: xml形式(推荐) 注解方式(个人喜欢注解,但是in场景可能不太适合注解) 代码: @Select("<script>" + & ...

  9. SQL Server基础知识三十三问 (7-14)

    8. 一般什么时候使用update_statistics命令? 答:  这个命令基本上是在很多数据被处理过了之后才使用的. 如果大量的删除, 修改, 或这大量的数据插入已经发生了, 那么index就需 ...

  10. Maximal Rectangle leetcode java

    题目: Given a 2D binary matrix filled with 0's and 1's, find the largest rectangle containing all ones ...