什么是引用
引用是一个别名,也就是某个已存在的变量的另一个名字。对某个对象的引用进行操作,就是直接对这个对象进行操作。
创建一个引用
创建一个引用的语句如下:
类型标识符 & 引用变量名 = 目标变量名;
例如:
// 原始变量
int a;
double b;
// 声明引用变量
int& ref_a = a;
double& ref_b = b;
我们尝试对原始变量赋值,并且打印原始变量和引用变量的值:
#include <iostream>
using namespace std;
int main(){
// 原始变量
int a;
double b;
// 声明引用变量
int& ref_a = a;
double& ref_b = b;
a = 9;
cout << "a:" << i << endl;
cout << "ref_a:" << r << endl;
b = 6.7;
cout << "b:" << d << endl;
cout << "ref_b:" << s << endl;
return 0;
}
编译运行,输出结果是:
a: 9
ref_a: 9
b: 6.7
ref_b: 6.7
这个输出结果是符合预期的。
引用的特点
与指针相区别,引用有以下的特点:
首先,不存在空引用。引用 只能也必须 在创建时被初始化为一个已存在的变量(连接到一块合法内存)。而创建指针时可以不赋初值,可以在任何时候被初始化,也可以为空。
int a = 9;
int& ref_a = a; // 正确,引用变量 ref_a 被初始化为 a
int& ref_a; // 错误,未给 ref_a 初值,编译会出错
第二,引用不能更换目标。一旦引用被初始化为一个对象,就不能被指向另一个对象。而指针可以在任何时候重新指向另一个对象。
double a = 17.09;
double b = 6.7;
double& ref_a = a; // 至此正确
double& ref_a = b; // 出错,不能多次指向
引用的应用
引用作为参数:以实现一个交换函数为例
下面我们以实现一个交换函数为例,对比指针和引用的使用方法。
void swap(__,__){
}
int main (){
double a = 17.09, b = 6.7;
swap(__,__);
return 0;
}
引用实现
void swap(double &x, double &y){
double temp;
temp = y;
y = x;
x = temp;
}
调用时使用:
swap(a,b);
指针实现
void swap(double *x, double *b){
double temp;
temp = *x;
*x = *y;
*y = temp;
}
调用时使用:
swap(&a,&b);
常引用
声明方式:const 类型标识符 & 引用变量名 = 目标变量名;
以 const 方式声明的引用,则不能通过引用对目标变量的值进行修改,从而使目标变量成为 const,比较安全。
int a;
const int &ref_a = a;
ref_a = 1; // 错误
a = 1; // 正确
引用作为返回值
声明方式:
类型标识符 & 函数名 (形参列表及类型说明){
函数体
}
当函数返回一个引用时,实际上返回一个指向返回值的隐式指针。这使得函数就可以放在赋值语句的左边。例如:
#include <iostream>
using namespace std;
int vals[] = {6, 0, 7};
int& setValues(int i){
return vals[i]; // 返回第 i 个元素的引用
}
int main(){
setValues(1) = 1; // 改变第 2 个元素
return 0;
}
更多细节
- 存在指针数组,但不存在引用数组,也不能建立数组的引用。
int* a[3] = {&x,&y,&z}; // 正确,定义了一个包含三个整型指针变量的指针数组 int& a[3] = {x,y,z}; // 错误,不存在引用数组 int b[2] = {6,7}; int& ref_b = b; // 错误,不能对数组的建立引用
- 引用本身不是一种数据类型,编译器不给引用分配存储单元。
-
区分
&
用作引用变量和用作取地址符。int a = 9; int& ref_a = a; // & 用于引用变量的创建 int b = 100; int *p_b; p_b = &N; // & 用作取地址符
&&r
&*p
不被接受,而*&p
可被接受。
例如,以下的程序是不被接受的。int a; int &&ref = a; // 错误 int &*p = a; // 错误
但是如下程序是正确的:
int *p; int *& q = p;
即
(int *)(&q) = p;
,相当于给指针 p 起了别名 q。-
引用在底层仍然是指针实现的,但引用更加符合面向对象和隐藏实现细节的原则,通过使用引用来替代指针,可以使 C++ 程序更容易阅读和维护,一定程度上避免了指针的几个缺点。例如指针可以为空,对指代对象不能为空的指针要做 null 检查,指针在赋值方面更加灵活,当然也更容易出错。
发表回复