Skip to main content

第31章 引用

引用(Reference)是C++语言特有的语法特性,它为已存在的变量提供一个别名,通过引用可以直接操作原变量。引用简化了指针的使用,提高了代码的可读性和安全性,在函数参数传递、返回值处理等场景中应用广泛。

31.1 引用的基本概念

31.1.1 定义

引用是一个变量的别名,它与被引用的变量共享同一块内存空间。定义引用时,需使用&符号,语法格式为:

类型& 引用名 = 变量名;

示例:

int a=10;
int& b=a;//声明b是a的引用(别名)

此时,b与a指向同一块内存,修改b的值会同时改变a的值,反之亦然:

b=20;
cout<<a;//输出20

31.1.2 特性

  1. 必须初始化:引用在定义时必须绑定到一个已存在的变量,不能只声明不赋值
int &r;// 错误:引用未初始化
int x=5;
int &r=x;// 正确:r绑定到x
  1. 一旦绑定不可更改:引用绑定变量后,无法再绑定其他变量
int a=10,b=20;
int &r = a;
r=b;// 不是修改绑定,只是把b的值赋值给a
  1. 不分配独立内存:引用无独立内存开销,编译器底层转化为指针,但语法层面屏蔽地址操作
  2. 类型严格匹配:引用类型必须和原变量完全一致
int a=10;
double &r=a;// 类型不匹配,编译报错

31.2 引用与指针的区别

对比项引用指针
定义语法类型& ref = 变量类型* p = &变量
初始化要求定义时必须绑定有效变量可先定义,后续赋值,可初始化为nullptr
能否更换指向绑定后永久不可变更可随时指向其他变量
解引用无需*,直接使用变量名必须*p解引用才能访问内容
空值不存在空引用存在空指针,解引用会崩溃
内存开销无额外内存(编译器优化)自身存储地址,占用内存
访问安全性无野引用风险易产生野指针、空指针崩溃

代码对比:

// 指针实现修改
int a=10;
int* p = &a;
*p=20;

// 引用实现修改
int a=10;
int &r=a;
r=20;

31.3 引用的应用场景

31.3.1 引用作为函数参数(传引用)

函数形参为引用时,传递的是变量本身,不会拷贝副本,函数内修改引用会直接改变外部实参,适合修改实参、传递大型对象减少拷贝。 交换函数示例:

void swap(int &x, int &y){
int temp = x;
x = y;
y = temp;
}
int main(){
int a=10,b=20;
swap(a,b);
cout<<a<<" "<<b;//输出20 10
return 0;
}

31.3.2 引用作为函数返回值

返回引用可以直接修改类成员等外部变量,禁止返回局部变量的引用(悬垂引用)

class MyClass{
private:
int value;
public:
MyClass (int v): value (v){}
// 返回成员变量引用
int &getValue(){
return value;
}
};
int main(){
MyClass obj(5);
obj.getValue()=10;//通过引用修改成员
cout << obj.getValue();//输出10
return 0;
}

错误示例(悬垂引用):

int &badFunc(){
int x=10;
return x;//函数结束x销毁,引用失效,未定义行为
}

31.3.3 常量引用 const &

语法:const 类型& 引用名 = 变量/常量 特性:无法通过引用修改原变量,但可以绑定常量、临时值,适合只读传参,无拷贝开销。

int a=10;
const int &r = a;
// r=20; 编译报错,不能修改原变量
a=20;//直接修改原变量合法

// 可绑定字面量、临时表达式
const int &r2=100;
const int &r3=5+3;

常量引用传参场景:

// 大型结构体,只读不拷贝
struct LargeObject{
int data[1000];
};
void print(const LargeObject &obj){
// obj.data[0]=1; 报错,禁止修改
cout << obj.data[0];
}

31.4 三种参数传递方式对比

  1. 值传递:拷贝副本,函数修改不影响外部,开销大(大对象)
void inc(int x){x++;}
  1. 指针传递:传递地址,可修改外部,语法繁琐,有空指针风险
void inc(int *x){(*x)++;}
  1. 引用传递:无拷贝,语法简洁,安全无空值;常量引用用于只读