← 学习库 C++程序设计教程 本册目录

第10章 引用

原书第 183 页

第10章 简明方便的别名代替——引用

在家里,父母为了方便召唤儿女,称呼儿女时会叫儿女的小名;在网络上,通常会用昵称代替本名;很多作者在发表文章时会用自己的笔名,等等。C++这门接近生活的高级算法语言也人性化地设置了简明方便的名称替代,即用别名(引用)代替真名(变量名或常量名),使C++程序更容易编写,性能更好,更贴近生活,下面就来详细介绍。

10.1 张三(真名)和小三(别名)是同一个人的例题详解

【例 10-1】假设真名张三是 x2,别名小三是 p,那么张三和小三是否是同一个人呢?下面从给这两个名赋值并显示二者的状态来比较区分。

1. 用心分析人想通,机随人行写提纲

按照题意,人的做法是:给某人起个真名为张三,又给张三这个人起个别名为小三,张三穿一套西服,看看小三同时也穿了这套西服;又给小三戴一付太阳镜,再看看张三呢?也戴着一副太阳镜,则张三和小三确实是同一个人,所以张三和小三的言行举止都是相同的。

2. 对号入座写文章,头脑运行改文章

编写程序如下:

//ex10-3-1.cpp
#include<iostream.h>
void main()
{
    double x2;//定义 x2,假设 x2 是真名张三
    double &p=x2;//&是引用声明符,声明 p 是 x2 的别名,即 p 是 x2 的引用,假设 p 是小名小三
    cout<<"请输入 x2 的值�";
    cin>>x2;//张三穿一套西服,小三同时也穿上了一套西服
    cout<<"x2="<<x2<<endl;//显示看看,一点也不假,因为张三和小三就是同一个人
    cout<<"p="<<p<<endl;
    cout<<"请输入 p 的值";//再验证一下
    cin>>p;//给小三戴上一付太阳镜
    cout<<"x2="<<x2<<endl;//张三也戴着这付太阳镜,名副其实就是同一个人了
    cout<<"p="<<p<<endl;
}

3. C++帮助且裁判,人定胜机凯歌扬

运行结果:

请输入 x2 的值:3

x2=3

原书第 184 页

p=3

请输入 p 的值:100

x2=100

p=100

结果正确。

请读者从此题中细细体会真名与别名之间的关系与效果。

引用非常容易使用,但为什么要用到引用,怎样声明引用,又怎样具体应用,请参考10.3节。

10.2 勤奋实践,总结评分

10.2.1 习题
  1. 编写计算一元二次方程的求根公式: $ x_{1,2}=\frac{-b\pm\sqrt{b^{2}-4ac}}{2a} $ 的程序,要求在主程序中输入一些参数,并用引用传递参数给子函数。在子函数中求一元二次方程的根,再将所求的根返回给主函数,并在主函数中输出结果。
  1. 用引用编写一个程序,在主函数中输入两个整数,调用一个求最大公约数和最小公倍数的子函数,并在主函数中输出结果。

3.有一个工程师,想设计一个长、宽和面积都较合适的房间,他想通过一个程序,在子函数中输入某个面积和长度值,并计算出宽度值,然后将这些值返回到主函数中打印输出以便挑选,请帮他实现。

4.在子函数中输入几个字符串,返回到主函数打印。运行程序,分别输入几位同学的学号、姓名和电话号码,观察结果。

5.用结构变量管理班里任意10个学生的高数成绩,信息包括学号、姓名和高数成绩,在子函数中找出高数成绩前3名的同学,并在主函数中打印这3名同学的信息。

  1. 编写一个程序,存储几个学生的姓名、电话和宿舍号的信息。查找时,当输入姓名就可以显示该同学三方面的信息。将查找到的同学的信息返回到主函数中打印。输入 5 个同学的姓名、电话和宿舍号,运行程序测试该程序的功能是否满足题意要求。
  1. 顾客想在商店中按单价查找商品,并把查找到的商品名称和单价返回主函数中打印,你可以帮他实现吗?假设已有第8章的第3题中某商店的商品信息。实际应用所编写的程序,看能否达到目的。
  1. 用引用做第8章的第6题,并返回主函数中打印书号及书名。
  1. 用引用做第8章的第7题,并返回主函数中打印冠军、亚军和季军。

10.用引用做第8章的第3题,将价格最低和最高的商品名称及单价返回到主函数中,并显示出来。

10.2.2 思考题
  1. 如果上述 10 道题目不用引用做行吗?
原书第 185 页
  1. 在子函数中用引用交换两个数据,在主函数中打印结果。
10.2.3 总结评分,继续提高

浏览、体验了例题、习题和思考题之后,说说自己的体会和收获,并认真总结,按表10-1给自己评判一下可以得多少分。

表10-1 总结评分表
成绩ABCD不足的原因改进的方法备注
C++知识完全理解和会用基本理解和会用肤浅理解和会用基本不理解和不会用
程序原创(独立编程)的比例(%)≥9080~8960~79<60

不论得分多少,大家都要总结经验,扬长避短,勤奋努力,不断提高。

最后浏览一下本章的第4节,可以先考考自己,然后再浏览,以便使重点知识掌握得更牢固。

10.3 引用知识

前面初步观赏到了引用只是用一个别名代替真名而已,那何时称呼别名,又怎么称呼呢?请一步一步地细细观赏就清楚了。

10.3.1 在什么情况下用到引用

虽说引用带来了简明方便,但也不能滥用,就像在家里称呼小名,在公众场所则一般还是用真名。在 C++ 中,大部分情况都用真名,而当有些处理用真名无法完成时,就加上别名代替——引用。

引用的最大好处是,在子函数的调用中通过引用可以将一个及一个以上的数据返回,而以前的子函数只能通过 return 语句返回一个数据。

10.3.2 关于引用

1. 引用是什么

引用只是个别名而已,是变量名、常量名或对象名(在第12章中会讲到)的别名。对变量名进行了引用后,变量名和引用名指的就是同一个数据量,不管是对变量名的操作还是对引用名的操作,都是对这同一个数据量进行操作,变量名和引用名的数值也是同步改变的,如例10-1。

2. 什么可以被引用

变量、常量和对象均可以被引用,但是,不能引用指针、数组和引用。

还可以对指针变量进行引用,如例 10-4 中实参传给形参:x→char *&m,即 “char *&m=x;”,m 是对指针变量 x 的引用,即 m 是指行变量 x 的别名。但不能写为 “char &*m=x;”,也就是引用了指针,这是错误的。记住:这方面的引用是:*在前,&在后。

原书第 186 页

3. 怎样声明引用

声明引用只需在声明语句中的变量名、常量名或对象名前加上“&”这个符号即可(引用对象请参考例12-6)。注意:在声明语句中且在“=”左边的“&”是声明引用,在其他地方用“&”都是取地址的操作(除了按位与“&”之外)。

【例10-2】

double x2;//定义真名 x2

double &p=x2;//声明 p 是 x2 的引用,即 p 是 x2 的别名

4. 怎样使用引用

别名(引用)的使用方法同真名(原名)的使用方法一样。

(1)对变量名和常量名的引用

【例 10-3】对常量名的引用实例。

//ex10-5.cpp
#include<iostream.h>
//void change(char *&,char *&);
void main()
{
    const double e=2.718;
    const double &exp1=e;//声明双精度常量 exp1 是 e 的别名
    cout<<"e="<<e<<endl;
    cout<<"expl="<exp1<<endl;
}

运行结果:

e=2.718

exp1=2.718

结果正确。

对变量名的引用见例 10-1。

(2)用于函数的参数传递中

见例 10-4 和例 10-5。

10.3.3 如何运用引用

根据上节所讲的应用场合,按需要与否,合理考虑是否加上引用。运用引用时要正确地声明和使用。

【例 10-4】用函数调用的方式交换两个不同长度的字符串指针,在主函数中定义两个字符串,并打印交换前的两个字符串;然后调用交换函数交换字符串指针,即换地址;最后返回主函数并打印交换后的两个字符串。例如,交换 “我要努力学习 C++。” 和 “我一定能成为 C++高手!” 这两个字符串。

(1) 用心分析人想通,机随人行写提纲

按照题意,人的做法同例7-8,只不过此题加了指针变量的引用作为形参,并采用了调

原书第 187 页

用交换子函数的方法。所以,其交换原理可参考图7-4。

主流程图和子流程图如图 10-1 和图 10-2 所示。

Image
图 10-1 主流程图
Image
图 10-2 子流程图

(2)对号入座写文章,头脑运行改文章程序代码如下:

//ex10-1.cpp
#include<iostream.h>
void change(char *&,char *&); //声明交换子函数
void main()
{
    char *x="我要努力学习 C++。";
    char *y="我一定能成为 C++高手!"; //定义两个字符串指针变量并初始化
    cout<<"交换前:"<<endl;
    cout<<"X="<<x<<endl;
    cout<<"Y="<<y<<endl;
    change(x,y); //调用交换子函数 change
    cout<<"交换后:"<<endl;
    cout<<"X="<<x<<endl;
    cout<<"Y="<<y<<endl;
}

void change(char *&m,char *&n)//同例7-8中交换指向红、蓝墨水瓶的地址的做法
{
    char *temp=m;
    m=n;
    n=temp;
}

例 10-4 中,声明了形参为指针变量的引用,两个字符串用字符指针 x 和 y 表示。传递到子函数 change 的实参是指针变量 x 和 y;在子函数中接收指针变量时用了指针变量的引用,即 m 是 x 的别名,n 是 y 的别名;交换子函数中对指针变量的引用交换了地址,即交换

原书第 188 页

指针对引用 m、n 的改动实际上就是对实参 x、y 的改动,则 x 变为 y 的地址,y 变为 x 的地址;在打印时,就打印交换后的地址的内容,所以输出结果就换过来了。

(3)C++帮助且裁判,人定胜机凯歌扬

上机实验记录如表10-2所示。

表 10-2 上机实验记录表
出错现象出错原因解决办法
cannot convert parameter 1 from 'char *' to 'char &' A reference that is not to 'const' cannot be bound to a non-lvalue将字符指针变量引用成了字符,类型不匹配将 char &改为 char *&,此错纠正

运行结果:

交换前:

X=我要努力学习 C++。

Y=我一定能成为 C++高手!

交换后:

X=我一定能成为 C++高手!

Y=我要努力学习 C++。

结果正确。

【例 10-5】将例 10-4 用另外一种解法实现(用字符串变量交换内容)。

程序代码如下:

人的做法与例 10-4 的区别在于,此题是交换内容,其做法同例 7-9,只不过此题加了引用和调用交换子函数的内容。

//ex10-2.cpp
#include<iostream>
#include<string>

using namespace std;

string temp;

void change(string &,string &();
void main()
{
    string x="我要努力学习 C++。";
    string y="我一定能成为 C++高手!"; //定义两个字符串变量并初始化
    cout<<"交换前:<<endl;
    cout<<"X="<<x<<endl;
    cout<<"Y="<<y<<endl;
    change(x,y); //调用交换子函数 change
    cout<<"交换后:<<endl;
    cout<<"X="<<x<<endl;
    cout<<"Y="<<y<<endl;
}

void change(string &m,string &n)//同例7-9中交换红、蓝墨水的做法
原书第 189 页
{
    temp=m;
    m=n;
    n=temp;
}

例 10-5 中用于交换的变量是字符串变量,而例 10-4 中是字符串指针变量。因为要返回两个字符串,所以用引用,即 m 是 x 的别名,n 是 y 的别名。运行结果同例 10-4。

10.4 引用的亮点

1. 在什么情况下用引用的亮点

在 C++ 中,大部分情况都用真名,而当有些处理用真名无法完成时,就加上别名代替——引用。

2. 引用具体知识的亮点

1)引用只是个别名而已。

2)不管是对变量名的操作还是对引用名的操作,都是对这同一个数据量进行操作,变量名和引用名的数值也是同步改变的。

3)变量、常量和对象均可以被引用,但是,不能引用指针、数组和引用。

4)声明引用只需在声明语句中的变量名、常量名或对象名前加上“&”这个符号即可。

3. 运用引用的亮点

1)别名(引用)的使用方法同真名(原名)的使用方法一样。

2)虽说引用带来了简明方便,但也不能滥用。

← 第9章 函数第11章 文件结构 →