引用就是某一变量(目标)的一个别名,对引用的操作与对变量直接操作完全一样。

引用的声明方法:类型标识符 &引用名=目标变量名;

【例1】:int a; int &ra=a; //定义引用ra,它是变量a的引用,即别名

说明:

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

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

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

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

ra=1; 等价于 a=1;

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

(6)不能建立数组的引用。因为数组是一个由若干个元素所组成的集合,所以无法建立一个数组的别名。
用(reference)是c++的初学者比较容易迷惑的概念。下面我们比较详细地讨论引用。

一、引用的概念

引用引入了对象的一个同义词。定义引用的表示方法与定义指针相似,只是用&代替了*。
例如: Point pt1(10,10);
Point &pt2=pt1; 定义了pt2为pt1的引用。通过这样的定义,pt1和pt2表示同一对象。
需要特别强调的是引用并不产生对象的副本,仅仅是对象的同义词。因此,当下面的语句执行后:
pt1.offset(2,2);
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[i]==Set2.elems[j])
{
res.elems[res.card++]=Set1.elems[i];
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[i]==Set2.elems[j])
{
res.elems[res.card++]=Set1.elems[i];
break;
}
return res;
}

三、引用返回值

如果一个函数返回了引用,那么该函数的调用也可以被赋值。这里有一函数,它拥有两个引用参数并返回一个双精度数的引用:
double &max(double &d1,double &d2)
{
return d1>d2?d1:d2;
}
由于max()函数返回一个对双精度数的引用,那么我们就可以用max() 来对其中较大的双精度数加1:
max(x,y)+=1.0;

C++数组引用

1 .在C++中可以定义数组的引用,用以解决C中无法解决的“数组降价”问题,我们先来看看什么是“数组降价”,先看如下代码:


void Test( char array[20] )
{
     cout << sizeof(array) << endl; // 输出 4
}

char array[20] = { 0 };
cout << sizeof(array) << endl; // 输出 20Test( array );

我们看到,对于同样的数组array,一个输出4,另一个输出20.这是因为void Test( char array[20] ) 中的array被降阶处理了,void Test( char array[20] ) 等同于 void Test( char array[] ) 也等同于void Test( char* const array ) 如果你原意,它甚至等同于void Test( char array[999] )

也就是说

void Test( char array[20] )

{

cout << sizeof(array) << endl;
    
}

被降成

void Test( char* const array )

{

cout << sizeof(array) << endl; // 既然是char*,当然输出4
    
}

这样以来,我们在函数声明中的数组大小限制是无效的,声明 void Test( char array[20] ) 并不能保证一定会接收到一个大小20的数组,即任何 char[] 都会被降价为 char* ,这样就增加了程序出错的可能性。要解决这样一个问题,我们可以用C++的数组引用作为参数,看以下代码:


void Test( char (&array)[20] )//是不是很像 char *p[20] 和 char (*p)[20] 的区别?
{
     cout << sizeof(array) << endl;
}

char array[20] = { 0 };
cout << sizeof(array) << endl;
Test( array );

这样 Test 函数就只能接收大小为 20 的 char[],看如下代码:
 …
char array1[10] = { 0 };
char array2[20] = { 0 };
Test(array1);//Error:实参不是大小为 10 的 char[]Test(array2);//OK

在 C++ 中,单纯的用数组的引用可以直接传递数组名,因为它将数组的大小已在形参里提供了信息。但是这样一来我们只能固定数组的大小来用这个函数了。用模板加数组的引用可以解决这个问题,看如下代码:
…t
emplate
void Test(int (&array)[sz])
{
    for (int i = 0; i < sz; ++i)
         cout << array[i] << endl;
}int a[2] = { 0 }, b[15] = { 0 };Test(a);//OKTest(b);//OK

只可惜任何事情都不会太完美,使用模板后确实可以使同一函数能够处理大小不同的数组了,扩大了函数的适用范围。但是这样定义的函数仍然存在着下述缺点:

1. 模板最终是要实例化的,所以调用多少个不同长度的数组,就要产生这个函数的多少份实例代码。而传统方式的函数只有一份实例,与函数的调用次数无关。

2. 不能应用于在编译期间数组的大小尚未确定的情况,这也使这个模板函数的适用范围受到限制。

3. 这样写的函数显然不能用指针变量作为函数的参数,因此不能用这个函数处理动态分配的内存区域。

C++的一般引用及其数组引用相关推荐

  1. java:java8新特性(Lambda 表达式、方法引用、构造器引用、数组引用、Stream API)

    速度更快 对 HashMap .ConcurrentHashMap低层的数据结构(数组+链表+二叉树) 低层的内存结构(将永久区更新为元空间,元空间使用的是物理内存) 代码更少(增加了新的语法 Lam ...

  2. 方法引用、构造器引用和数组引用

    方法引用 若 Lambda 体中的内有方法已经实现了,我们可以使用"方法引用"(可以理解为方法引用是 Lambda 表达式的另外一种表现形式) 语法格式 主要有以下三种语法格式: ...

  3. java8 构造函数引用_java8新特性之方法引用与构造器引用

    方法引用与构造器引用 关于lambda表达式,我们已经知道了,一般是有两部分组成.箭头操作符(->)左侧是lambda体的参数列表,右侧是lambda体,而lambda体里面的操作,有些情况下可 ...

  4. 数组引用以避免数组降阶(c++)

    数组降阶是个讨厌的事,这在C语言中是个无法解决的问题,先看一段代码,了解什么是"数组降阶" #include <IOSTREAM> using namespace st ...

  5. c++ 数组引用_在 Solidity中使用值数组以降低 gas 消耗

    背景 我们Datona Labs在开发和测试Solidity数据访问合约(S-DAC:Smart-Data-Access-Contract)模板过程中,经常需要使用只有很小数值的小数组(数组元素个数少 ...

  6. 提高Java表达能力!不落伍一起掌握Java8中Lambda表达式、函数式接口及方法构造器数组引用

    文章目录 函数式接口概述 函数式接口示例 内置函数式接口 Lambda简述 Lambda语法 方法引用 构造器引用 数组引用 函数式接口概述 只包含一个抽象方法的接口,称为函数式接口. 可以通过 La ...

  7. 集合——对象数组(引用数据类型数组)

    案例:我有5个学生,请把这个5个学生的信息存储到引用数据类型数组中,并遍历数组,获取得到每一个学生的信息. 思路分析:首先,想要创建学生对象,就得有学生这个类,所以,首先创建一个包(package c ...

  8. c语言程序定义不知数量的一维数组,c语言程序设计10-第6章 利用数组处理批量数据 6.1 怎样定义和引用一维数组.ppt...

    c语言程序设计10-第6章 利用数组处理批量数据 6.1 怎样定义和引用一维数组 * 临沂大学汽车学院:韩晓翠 第6章 利用数组处理批量数据 6.1 怎样定义和引用一维数组 授课要点 数组的概念 一维 ...

  9. 怎样定义和引用一维数组,二维数组

    s1,s2,s3,...,s30 右下角的数字称为下标(subscript) 一批具有同名的同属性的数据就组成了一个数组(array),s就是数组名. 1.怎样定义和引用一维数组 一维数组.二维数组. ...

最新文章

  1. Go实战--也许最快的Go语言Web框架kataras/iris初识三(Redis、leveldb、BoltDB)
  2. 私.Modbus测试_ZC02_串口方式
  3. 数组的定义格式一_动态初始化
  4. 互联网账户系统如何设计
  5. 微型计算机接口与技术的交通灯,微机原理及接口技术课程设计交通灯
  6. 保留小数点位数和格式
  7. 注册、登陆、审核练习
  8. 51单片机学习——1天学完普中基本实验例程,走马观花式学习,大家切勿效仿。
  9. 地平线开源网站源码Deepsoon v1.2.3
  10. ps制作干净通透欧美风格图片
  11. c语言指针 汇编间接寻址,C语言指针和汇编语言间接寻址的关省略探讨从存储空间图的视角加以分析.pdf...
  12. c# 基于BouncyCastle.Crypto的国密sm2,sm4封装,与java版本兼容
  13. Excel技能培训之六-定位功能,隔行插入删除空行,分组插入空行,高亮行列间差异,复制筛选后的数据
  14. 手机选择之我见——需求分析
  15. STM32DAC输出遇到的问题
  16. Esp8266进阶之路14 esp8266的 FreeRtos系统学习的正确姿势,环境配置环境、烧录。(附带demo)
  17. 二刷剑指Offer:剑指Offer+LeetCode(全53题)
  18. 迷茫?生命科学如何破局冰山!道翰天琼认知智能机器人平台API接口大脑为您揭秘-64
  19. 最近压力大?一波毒鸡汤帮你调整回来
  20. 网页上的漂浮物制作代码

热门文章

  1. 力扣Java解数独_LeetCode 力扣 37. 解数独
  2. JS - JSON对象与JSON字符串相互转换的几种方法
  3. (Java)Integer类的其他常用方法
  4. 【C++深度剖析教程27】多态的概念与意义
  5. BUUOJ reverse SimpleRev (爆破)
  6. 创建好centos7虚拟机之后连xshell连不上虚机
  7. 什么是慢查询?如何通过慢查询日志优化?
  8. MySQL数据导入导出(一)
  9. 新手算法学习之路----二分法Last-position-of-Target
  10. NET Core 指令启动