GESP 6级

引用

6级 · 指针/STL/复杂度
💡 为什么重要

引用(Reference)是C++对C语言指针的"安全升级"。在函数传参、运算符重载、STL容器操作中,引用无处不在。GESP 6级考试经常考引用传参与值传参的区别。掌握引用后,你写出来的代码会比用指针更简洁、更安全。

📖 前置知识
  • 指针基础(上一节的内容:& 取地址、* 解引用)
  • 函数的定义和调用
  • 值传参的概念(函数参数是副本)
🔍 什么是"引用"?

引用就是一个变量的别名。它不像指针那样存地址,而是直接"绑定"到原变量上——引用和原变量是同一个人的两个名字。

打个比方:假设你叫"小明",你还有个外号叫"小明子"。"小明"和"小明子"是同一个人。引用就像这个外号。

核心规则:

  • 引用必须在声明时初始化(必须一开始就绑定一个变量)
  • 引用一旦绑定,不能改成绑定其他变量
  • 引用不能为空(不像指针可以为 nullptr)
  • 对引用的任何操作,都是直接操作原变量
📐 核心语法
int a = 10;
int &r = a; // r 是 a 的别名
r = 20; // a 也变成20(因为r就是a)
cout << r; // 输出20
cout << a; // 输出20

声明语法:类型 & 引用名 = 原变量;
💻 代码详解
📝 示例1:引用的基本使用
#include <iostream>
using namespace std;

int main() {
    int a = 10;

    // 创建引用r,作为a的别名
    int &r = a;   // r 和 a 指向同一块内存

    cout << a << endl;  // 输出10
    cout << r << endl;  // 输出10(r就是a,值一样)

    r = 50;              // 通过r修改值
    cout << a << endl;  // 输出50(a也被改了!因为r就是a)

    a = 100;             // 通过a修改值
    cout << r << endl;  // 输出100(r也跟着变了)

    // 注意:r 不占额外内存,它和 a 是同一个地方
    // &r == &a 为 true(地址相同)

    return 0;
}
📝 示例2:引用作为函数参数(最常见用途)
#include <iostream>
using namespace std;

// 用引用实现swap:参数是原变量的别名,直接修改
void swap(int &a, int &b) {
    // a 是 x 的别名,b 是 y 的别名
    int t = a;   // 保存a(即x)的值
    a = b;       // 把b(即y)的值赋给a(即x)
    b = t;       // 把保存的值赋给b(即y)
}

int main() {
    int x = 1, y = 2;

    cout << "交换前: x=" << x << ", y=" << y << endl;
    // 输出: 交换前: x=1, y=2

    swap(x, y);  // x和y的别名传入函数

    cout << "交换后: x=" << x << ", y=" << y << endl;
    // 输出: 交换后: x=2, y=1

    return 0;
}
📝 示例3:引用 vs 指针的对比
#include <iostream>
using namespace std;

// 指针版本:需要传地址,函数内用 -> 或 * 访问
void printByPointer(int *p) {
    cout << *p << endl;   // 要用解引用
}

// 引用版本:直接传,函数内当普通变量用
void printByReference(int &r) {
    cout << r << endl;    // 直接用,简洁!
}

int main() {
    int a = 42;

    printByPointer(&a);     // 要加 & 取地址
    printByReference(a);     // 直接传,更方便

    // 引用 vs 指针的区别:
    // 1. 引用不能为空,指针可以为 nullptr
    // 2. 引用不能改指向,指针可以重新指向其他变量
    // 3. 引用使用时不需要 * 解引用,更简洁
    // 4. 函数参数优先用引用,更安全

    return 0;
}
📝 示例4:const 引用(常引用)
#include <iostream>
using namespace std;

// const引用:只能读,不能改
void print(const int &r) {
    cout << r << endl;
    // r = 100;  // 错误!const引用不能修改
}

int main() {
    int a = 42;
    const int &r = a;  // 常引用

    cout << r << endl;  // 输出42,可以读
    // r = 100;          // 错误!不能通过常引用修改

    a = 100;             // 但可以直接修改a本身
    cout << r << endl;  // 输出100

    print(a);             // 传参时常用 const 引用
    // 好处:不复制数据(高效),又保证不被修改(安全)

    return 0;
}
⚠️ 易错点
  • 引用声明时不写 &:int &r = a; 的 & 是声明引用的语法,不是取地址!只在声明时才有这个含义
  • 引用不初始化:int &r; 是错误的!引用必须在声明时就绑定一个变量
  • 引用绑定了就不能改:int a=1, b=2; int &r=a; r=b; —— 这不会让r变成b的引用,而是把b的值赋给a,a变成2
  • 值传参 vs 引用传参混淆:如果函数参数不加 &(如 void f(int a)),函数内修改 a 不会影响外面的变量
  • 把引用和指针搞混:引用是别名,不是指针。引用不能做 p++、不能为 null、不能重新绑定
🎯 练习建议
  • 入门:写一个 swap 函数,分别用值传参、指针传参、引用传参三种方式实现,对比效果
  • 进阶:写一个函数用引用同时返回两个值(如求两个数的和与差)
  • 思考:为什么标准库的 sort、push_back 等函数参数都用引用?
  • 对比练习:写两个版本的函数,一个传值一个传引用,观察传递大型结构体时的性能差异