C++随记(七)--引用变量

C++随记(七)--引用变量

引用变量是C++新增的一种复合类型。引用是 已定义的变量的一个别名(另一个名称)。引用变量的主要用途是用作函数的形参,如果将引用变量作参数,那么就相当于是在对原始变量进行直接操作。

1、引用变量的创建

int Bruce_Wayne;
int & Batman = Bruce_Wayne;

首先我们有一个int 类型的变量:Bruce_Wayne,然后我们定义了一个引用变量:Batman,上述声明允许将Bruce_Wayne和Batman互换,因为它们指向相同的值和内存单元!所以Batman就是Bruce_Wayne,Bruce_Wayne就是Batman。 符号 int &表示符合类型—引用,而且是一个指向int变量的引用。

注意:引用必须在声明的同时进行初始化!

int Bruce_Wayne;
int & Batman;
Batman = Bruce_Wayne;//非法,引用必须要在声明的同时进行初始化,一旦与某个变量关联起来,就必须一直效忠于它。

2、引用作为函数参数

引用经常被作为函数参数,使得函数中的变量名成为调用程序中的变量的别名。这种传递函数的方法叫做----按引用传递。 按引用传递允许被调用的函数能够访问调用函数中的变量。 区别于C语言,C语言提供了按值传递,导致被调用函数使用调用程序的值的拷贝。 当然,C语言也提供了按指针传递来避开按值传递的方式。

简单例子:

void swap1( int & a, int & b)
{
int temp;
temp = a;
a =b;
b =temp;
}

void swap2( int a, int b)
{
 int temp;
 temp = a;
 a = b;
 b = temp;
}

比较这两个函数,唯一不同的地方就是在函数头的位置,前者是引用变量作形参。

假设现在使用这两个函数

swap1( AAA, BBB);//设AAA,BBB是我已经定义好了的int 变量
swap2( AAA, BBB);

能实现二者的值交换的,只有第一个函数,因为第二个函数中的a、b是拷贝了AAA、BBB的值,然后实现大量a、b自己的交换,但是没有对AAA、BBB造成影响,而第一个函数使用引用作为形参,那么第一个函数中的a、b就可以当作是AAA、BBB,所以我实际是在对AAA、BBB进行操作,这就是引用的妙处。 顺便说一句,这里并没有违反引用要在声明的同时初始化的原则,因为函数调用的时候,自动就使用实参来初始化形参。

要注意,一般情况下,将引用变量作形参时,实参应该为变量,例如我这里的AAA、BBB都是int类型的变量,而不能将表达式比如x+3 这种拿来作实参,现在的大多数编译器都会指出这一错误

3、常引用

常引用也是一个非常有用的技巧,我们上面谈到,引用变量和原变量是一回事,也就是说我如果在函数中对引用变量进行操作,就能改变原来的变量,我上面交换数值的函数用的就是这一性质,但是有时候我们会希望避免函数中一些操作对我的原变量产生影响,导致无意中修改了变量数值,那么就可以考虑常引用。 常引用声明方式:const  类型标识符 & 引用名 = 目标变量名; 例如有一函数为:

void exam( const int & a )
{
…
}

那么就表明在此函数中, 引用变量 a 是不能改变值的,这样就能规避a的改变导致我原来作为实参的原变量的改变,整个函数中,可以利用的就只是a的确定的值。

你可能会有疑问,既然只用到了形参的值,那么按值传递不就可以了吗?比如:

void exam(int a )
{
…
}

这样既能够把实参的值传递进来给a,而且也不用担心a的改变会影响原实参的数值。这么考虑确实是对的,但是注意一个问题,我如果使用按值传递的方法,我是创建了新的变量的!即int a 这一步,我会开辟一个新的内存空间来存放值,函数调用完之后又一般会释放这个值。而我的引用呢?const int & a没有创建新的变量!a仍然使用原来实参的储存空间和地址!也就是我没有创建变量这一过程。

在程序运行中,创建新变量消耗的时间是很多的,当然这里的int变量可能感受不到,但是当你的引用类型是结构体、类的时候,你就能明显感觉到了,我曾经把一个程序中的这些按值传递的都改成了常引用,发现最后程序快了几秒!这已经是很可观的了,因为我的程序总共就运行几十秒的时间(当时在千方百计减少程序的运行时间,还是我的老师点拨了我一下)。

所以常引用的优势在于:既保护了原来的实参受到误修改,又充分提升了效率节省了空间!

4、函数返回值为引用

先来看两个函数的对比:

int test1( int a, int b, int sum)
{
  sum = a + b+ sum;
  return sum;
}
//////////////////////////////////////////////////
int & test2( int a, int b, int & sum)
{
  sum = a+b;
  return sum;
}

这两个函数有什么不同呢? 很明显test2 的函数头多了两个 &,这就是函数返回值为引用的意思。首先看到函数被声明为 int & test2, 且参数列表中也至少有一个引用变量作形参, int & sum。

现在来分析这两个函数运行时的区别,

情况①:

int Price = test1( price_1, price_2, result);

首先,price_1, price_2把值传递给a和b,result的值传递给sum,然后经过计算,sum的结果被函数返回,此时将结果复制到一个临时的位置,然后将此值再赋值给 Price。

情况②:

int Price = test2( price_1, price_2, result);

同样price_1, price_2把值传递给a和b,而sum此时是作为result的引用值,所以相当于直接把result拿进去参与计算(当然这不是重点),重点是:result由于和sum是一回事,因此sum被修改后,result也更新了,函数return sum,实际就是return result,所以不需将值复制到一个临时的位置,而是相当于直接把result的值,复制给Price!

同时你会发现当返回值为引用时,以下语句是合法的:

test2( price_1, price_2, result) = 33;

看起来是在对函数赋值,但是这个函数实际上是 result 的别名,所以其实你会发现result的值被修改为33. 当然,如果你不希望返回的引用值出现修改的情况,可以使用const:

const int & test2( int a, int b, int & sum){....}

这样再对其赋值就不合法了,因为定义为了const,所以返回的引用就不能被修改了。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏恰同学骚年

正则表达式30分钟入门教程--deerchao

原文地址:http://www.cnblogs.com/deerchao/archive/2006/08/24/zhengzhe30fengzhongjiaoc...

1124
来自专栏机器学习算法与Python学习

Python最简编码规范

1496
来自专栏菜鸟致敬

一分钟带你读懂Python中的三类特殊方法

在Python中有着三类特殊方法:静态方法、类方法以及抽象方法。今天我们来谈谈其中的这三类特殊方法。

452
来自专栏静默虚空的博客

字符串 模式匹配

要点 模式匹配是数据结构中字符串的一种基本运算,给定一个子串,要求在某个字符串中找出与该子串相同的所有子串,这就是模式匹配。 假设P是给定的子串,T是待查找的字...

1778
来自专栏思考的代码世界

Python编程从入门到实践之函数2|第9天

向函数传递列表很有用,这种列表包含的可能是名字、数字或更复杂的对象(如字典)。将列表传递给函数后,函数就能直接访问其内容。

3567
来自专栏北京马哥教育

Python最简编码规范

1687
来自专栏深度学习之tensorflow实战篇

Python--学习旅程5

一、数据结构 Python中存在三种重要的数据结构,即列表、元组和字典,下面将一一介绍这三种数据结构。 列表: 列表是处理一组有序项目的数据结构,每个项目之间...

2786
来自专栏Android干货

浅谈Kotlin(二):基本类型、基本语法、代码风格

1223
来自专栏陈树义

从 HelloWorld 看 Java 字节码文件结构

很多时候,我们都是从代码层面去学习如何编程,却很少去看看一个个 Java 代码背后到底是什么。今天就让我们从一个最简单的 Hello World 开始看一看 J...

3827
来自专栏程序员互动联盟

【C语言基础】结构体赋值

结构体在 C 程序中使用的较为频繁,能对数据有一定的封装的作用。对一个结构体赋值时,经常采用的方式是,分别对其成员变量赋值。那么能否将一个结构体用赋值号(“=”...

2907

扫码关注云+社区