大白话说C++——“引用”是个啥?

一、引用是什么?

        引用就是给已经存在的变量取个别名,也就是取外号。比如说,班级里有一个小孩叫赵铁柱,人高马大打篮球很好,人称“二班奥尼尔”。当这个外号被大家熟知后,那讨论到他时,不管是说“赵铁柱昨天和姑娘表白了”还是“二班那个奥尼尔被女生发好人卡了”,大家都知道指的是谁。同样,假设我们已经定义了一个叫做a的变量,但是在某些场合人们更习惯叫这个变量为b,那就可以通过引用的方式,给a取个外号叫b。但是就像不管取多少外号,我们都知道这说的是一个人一样,不论一个变量有多少个引用,它在内存中都只有一个存储位置,存储的数值都是一样的。所以,对引用的操作,其实就是对本体的操作。

 

二、引用咋写?

引用的写法用到了符号 & 。这个符号在C++里用处广泛,有时候表示与条件(&&),有时候表示取地址,但在这里,它有了船(全)森(新)的用法:给变量取外号(创建变量的引用)。

我们知道,英美两国的英语单词在某些时候不一样。比如在英国,老绅士们管秋天叫autumn;但到了美国一些地方,美国老铁会亲切地称秋天为fall。为了照顾两国人民,,我们要让秋天有两个名字,但是归根到底,秋天就是秋天嘛。那这时候 ,引用该怎么处理呢?

int autumn;            //英国人:这是我说的秋天
int & fall = autumn;   //美国人:俺也一样!

看到了吗?定义引用三部曲:

1、写出引用类型(int)

2、亮出引用身份(&)

3、给出引用名称(fall)

这里,& 这个符号和int一起,表示定义了一个指向int的引用。至此,我们就可以愉快地混用autumn和fall而不用顾忌两国人民因为秋天的叫法不同而吵架了。

我们做个试验:

#include <iostream>
using namespace std;

int main()
{   
    int autumn = 90;
    int & fall = autumn;
    cout << "British: autumn last " << autumn << " days." << endl;
    cout << "American: fall last " << fall << " days." << endl;
    autumn++;
    cout << "British: In this year, autumn last " << autumn << " days." << endl;
    cout << "American: yes, I agree with you, fall last " << fall << " days." << endl; 

    cout << "The address of autumn is " << &autumn << endl;
    cout << "The address of fall is " << &fall << endl;
}

上述代码运行的结果是:

从上面的结果可以看到,autumn和fall这两个名称在内存中的地址都是一样的,表示他就是一个变量的两个名称。对其中一个进行操作,另外一个也受到同样的影响。

 

三、为啥要用引用?

1、引用让程序猿可以在调用函数里修改数据对象

当引用作为函数参数时,我们将这种传递方式称为按引用传递。用了按引用传递的方式后,被调用函数和调用的函数用的变量就是同一个,而不是一个副本了。比如:

void func1()
{
    int value1, value2;
    value1 = value2 = 0;
    func2(a, b);
}

void func2(int& a, int& b)
{
    //some other operation...
}

在func2函数中,a和b分别是func1的value1和value2的引用,对a和b的操作也会同样改变value1和value2的特性。

2、用引用传递结构比较大的结构或类,可以让程序运行速度-1s加快

当传入调用函数的结构体或者类很大,那么使用引用来传递可以加快调用函数的运行速度。这个也很好理解,函数就不用再复制数据了,多余的操作就关闭了,函数的执行效率又占领高地了。当然,如果配合const使用,效果会更安全。

 

四、引用有啥要注意的地方?

说到这里,那我们在取外号(划掉)创建引用的时候有什么要注意的吗?

1、引用声明的时候就要初始化

      这条很好理解。套用成语,“皮之不存,毛将焉附”,引用说白了就是一个变量的“外号”,如果没有原始变量这个本体,外号又有什么存在的意义呢?所以,下面的情况(第二行)是绝对绝对不可以的!

      这一条包含两点内涵:一是引用不能不进行初始化,二是引用不可以先声明再赋值。下面第三行是引用的正确打开方式。

int value = 1;
int & wrongUseOfReference;
int & rightUseOfReference = value;

 2、引用可以通过初始化设置,但是不能通过赋值设置

      这又怎么理解呢?我们简单做这样一个实验。

      现在英国和美国人就秋天的看法达成一致了;现在中国也要加入,并准备用“qiutian”代指秋天。那在去用fall来代指秋天可以吗?看例子:

#include <iostream>
using namespace std;

int main()
{
	int autumn = 90;
	int & fall = autumn;  // 初始化的时候设置了引用
	cout << "British: autumn last " << autumn << " days." << endl;
	cout << "American: fall last " << fall << " days." << endl;
	cout << "autumn address is " << &autumn << endl;
	cout << "fall address is " << &fall << endl;

	int qiutian = 91;
	fall = qiutian;  // 通过赋值设置引用
	cout << "British: autumn last " << autumn << " days." << endl;
	cout << "American: fall last " << fall << " days." << endl;
	cout << "Chinese: qiutian last " << qiutian << " days." << endl;
	cout << "autumn address is " << &autumn << endl;
	cout << "fall address is " << &fall << endl;
	cout << "qiutian address is " << &qiutian << endl;
}

看运行完的结果:

乍一看,fall确实变成了秋天的别名:值从90变成91了嘛!但我们定眼一看,发现不对!fall还是和autumn有同样的地址,但是和qiutian的地址不一样。所以说,fall = qiutian 这句话其实就是一个朴实无华且枯燥的赋值,并没有实现引用的效果。一句话,引用一旦出生了,就只能跟随一个变量。

 

3、当原始数据想发生改变时,使用按引用传递

       老规矩,上例子。现在有一个函数,想计算传入参数的立方,当我们用引用传参的时候:

#include <iostream>
using namespace std;

double cube(double & value);

int main()
{
	double param = 4.0;
	cout << cube(param);
	cout << " is cube of " << param;
}

double cube(double & value)
{
	value *= value * value;
	return value;
}

得到的输出是:

在这里,cube函数中value是main函数中param的引用,cube的过程改变了value的值,同时也改变了param的值。

那怎样防止呢?我们可以使用值传递,这样,cube里折腾的value是main函数中param的复制品,不论value如何折腾,param自岿然不动:

#include <iostream>
using namespace std;

double cube(double  value);

int main()
{
	double param = 4.0;
	cout << cube(param);
	cout << " is cube of " << param;
}

double cube(double  value)
{
	value *= value * value;
	return value;
}

这样的结果是:

或者可以用const对传入引用进行限制,以一种“霸道总裁”的方式告诉cube函数:你不能对我传给你的引用做修改:

#include <iostream>
using namespace std;

double cube(const double & value);

int main()
{
	double param = 4.0;
	cout << cube(param);
	cout << " is cube of " << param;
}

double cube(const double & value)
{
	double result = value * value * value;
	return result;
}

和上面值传递也有同样的效果。这时,再写成 value *= value * value就会出编译错误,因为这个时候涉嫌非法修改const引用。由此看来,const是一种非常实用的保护措施。

4、如果传递的数据对象是数组,只能使用指针,不能用引用了

(未完待续)

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值