C++新增了一种复合类型————引用变量。
引用是已定义的变量的别名。引用是C++引入的新语言特性,是C++常用的一个重要内容之一,正确、灵活地使用引用,可以使程序简洁、高效,掌握C++的&符号,是提高代码执行效率和增强代码质量的一个很好的办法。
1:创建引用变量。
int sasuke = 10;
int & naruto = sasuke; //创建引用变量
注意: &运算符不是地址运算符,而是将naruto的类型声明为int& (int类型的引用);
错误示例
int & sakura;
sakura = sasuke
注意:引用变量创建时候,必须对其进行初始化。
//测试引用的使用
#include <iostream>
#include <string>
#include <iomanip>
using std::cout;
using std::cin;
using std::endl;
using std::string;
using std::setw;
int main()
{
int sasuke = 10;
int kakashi = 9;
int & naruto = sasuke; //创建引用变量
cout << "naruto = " <<naruto << endl;
cout << "Sasuke's adress: "<< &sasuke << setw(20) << "Naruto's adress: "<< &naruto << endl;
//int & Sakura; //错误: 引用变量必须在声明的时候进行初始化
naruto = kakashi; //将变量 naruto 和 变量kakashi 连接
cout << "naruto = " << naruto << endl; //输出naruto 和 sasuke的值不难发现,二者的值都改变为9
cout << "sasuke = " << sasuke << endl;
cout << "Kakashi's address: " << &kakashi << endl;
cout << "Sasuke's adress: "<< &sasuke << setw(20) << "Naruto's adress: "<< &naruto << endl;
//仔细观察输出我们不难发现,naruto,sasuke的地址都没发生变化。
return 0;
}
2:引用用作函数参数
将引用用作函数参数传递的方法称为按引用传递。C语言在进行参数传递的时候往往是按值传递,按值传递的行为导致被调用的函数使用的是值得拷贝。当然C也提供了避开按值传递的限制,比如按指针传递。
是一个按值传递的例子
void swap(int & a, int & b)
{
int temp;
temp = a;
a = b;
b = temp;
}
int main()
{
int sasuke = 10;
int kakashi = 9;
cout << "Before change: \n" << " sasuke = " << sasuke << " kakashi = " << kakashi << endl;
swap(sasuke, kakashi);
cout << "Before change: \n" << " sasuke = " << sasuke << " kakashi = " << kakashi << endl;
return 0;
}
3:引用过程中的临时变量
如果实参与引用类型不匹配,C++便会产生临时变量,前提是引用必须是常引用。
下面我们来看一个简单的例子。
从这个程序中,我们不难发现程序报告了一个类型异常的错误。因为我们的函数需要int类型的引用,而在main()函数中,我们给了add函数两个double型的变量。这好像和我们的小标题不相符,临时变量在哪里呢?我们来看下一段代码。
仔细观察哪里发生了变化,没错,我只是简单的在add函数里加上了const关键字,程序便能顺利运行。那么这是为什么呢?通过输出两个变量的地址我们不难发现,前后两个a b 的地址发生了变化,也就是产生了临时变量。
因此当引用声明为const类型,并且能转换为正确的类型的时候,可以通过生成匿名的临时变量使得程序正确运行。
4:引用用作返回值
返回引用和传统的返回机制有什么不同?为什么要使用引用作为返回值?传统返回机制与按值传递函数参数类似:计算关键字return后面的表达式,并将结果返回给函数。这其实是一个将值复制到临时位置,而调用程序使用这个值得过程。返回引用时候实际上返回的是被引用的变量的别名,省去了复制临时变量的过程,因此效率更高。
那么是不是将引用作为返回值就是十全十美的呢? 显然不是,下面我们来看看引用有哪些危险的地方。
const int & add(int & a, int & b)
{
int temp = a + b;
return temp;
}
这个函数好像没有什么问题,但是仔细观察我们发现temp变量在函数执行结束之后便被销毁,这很可能会导致一系列的问题。
因此,将引用作为函数返回值得时候,应尽量避免返回函数终止时不再存在的内存单元引用。
5:引用用于类对象
谈到C++,我们自然不能将类这个话题给省略掉,那么引用如何在类中大显身手呢?
我们经常使用引用来传递类的参数。比如我们熟悉的复制构造函数就是一个典型的例子。
void showName(const string & firstname, const string & lastname)
{
cout << "Name:" << firstname<< " "<< lastname << endl;
}
int main()
{
string fname;
string lname;
cout << "Please input your firstname:\n";
getline(cin, fname);
cout << "Please input your lastname:\n";
cin >> lname;
cout << "we are going to show your name:\n";
showName( fname, lname);
showName("Dong","Jiaxu");
return 0;
}
在这个显示姓名的例子中, 我们将string类的对象引用作为函数参数,来进行内部操作。
PS(C风格的字符串作为string类对象引用参数)return语句前面我用绿色标注了一行代码,如果你是个C++新手,你可能会疑惑,为什么这样可以呢?我们明明需要的是string对象啊。string对象定义了一种从char * string的转换,因此我们能很简单的用C风格的字符串来初始化string类对象,在将char * 或 const char * 传递给 形参 const string &的过程中,程序会创建一个正确的临时变量,继续进行操作。
当我们将类对象作为函数参数进行传递或将类对象作为返回值的时候,如果使用引用会省下产生临时变量所需要的时间,因此提高了效率,而且在被调函数中我们能通过类对象直接对主调函数中的类对象进行修改。
引用总结:
1:单纯给某个变量设计别名是无意义的,引用设计初衷就是在函数中进行参数传递,解决大型数据块或对象的传递效率问题。
2:引用和指针相比,显著提高了程序的可读性,无需如同指针一般对变量进行间接操作。
3:引用传递没有临时变量产生,提高了效率,而且还能通过const保证引用的安全性。
4:声明引用后,变量实际上有两个名称,即原目标名称和引用名,而且不能再把该引用名作为其他变量名的别名。
5:声明引用并不是新建立了一个变量,它只表示该引用目标变量名的别名,它本身不是数据类,因此引用本省不占存储单元,系统也不会给引用分配存储单元。
6:不能建立数组的引用。数组是若干个元素集合,无法建立一个数组的别名。