引用入门
更新时间:2026-08-27。本文是
languages/cpp/主题入门层第 13 篇。引用是 C++ 相对 C 新增的第一个"有自己性格"的概念:它是变量的别名,用起来像值、行为像指针。这一篇先把它本身讲清楚——必须初始化、不能重新绑定、和指针的恩怨——下一篇再讲它怎么用在函数参数上。
本文要回答的问题
- 引用到底是什么?跟指针什么关系?
- 为什么引用必须初始化、不能"换绑"?
- 什么时候用引用、什么时候用指针?
一、引用是别名
int x = 10;
int& ref = x; // ref 是 x 的引用(别名)
ref = 20; // 改 ref 就是改 x
std::cout << x; // 20int& 读作"int 的引用"。ref 和 x 指向同一块内存,不存在两份数据。想验证?取地址:
std::cout << &x << "\n"; // 0x...
std::cout << &ref << "\n"; // 一模一样ref 不是 x 的拷贝,是 x 的另一个名字。这句直觉最重要,后面所有引用相关的行为都从它推出。
二、两条铁律
- 必须初始化:
int& ref; // 错误:引用必须绑定到一个对象
int& ref = x; // 正确引用没有"空引用",不存在"还没绑定"的状态。这跟指针的 int* p;(可以暂时不赋值、可以是 nullptr)形成鲜明对比。
- 不能重新绑定:
int a = 1, b = 2;
int& r = a;
r = b; // 不是让 r 改绑到 b!是把 b 的值 2 赋给 a
// 现在 a == 2, b == 2, r 仍然引用 ar = b 这个语句让很多人懵:看着像"把 r 绑到 b",实际是"把 b 的值写进 r 指向的地方"。引用一辈子只认第一次绑定的对象。想要"能换绑的引用",那就用指针。
三、引用 vs 指针:一张表
| 对比项 | 引用 int& | 指针 int* |
|---|---|---|
| 本质 | 别名 | 存地址的变量 |
| 必须初始化 | 是 | 否(可为 nullptr) |
| 能否换绑 | 不能 | 能 |
| 空值 | 没有空引用 | nullptr |
| 访问方式 | 直接用(自动解引用) | 用 * 解引用 |
| 语法开销 | 无,天然像值 | 注意 * 和 -> |
| 数组/动态内存 | 不适合 | 适合 |
内存里两者其实"长得一样"——引用在底层通常就是个指针,只是编译器替你把解引用的活干了,还顺手加了两条铁律管住你。语法上引用舒服,能力上指针更野。
四、底层长得像指针(但别依赖直觉)
int x = 10;
int& ref = x; // 底层:ref 存着 x 的地址
void foo(int& r) { // 传引用,底层传的是地址
r += 1; // 编译器自动解引用
}把引用想成"编译器帮你自动解引用的指针",绝大多数行为都解释得通。但它和指针在语义上有质的不同:引用保证有效(初始化时就绑定了),指针可能悬空、可能为空——所以现代 C++ 的口头禅是"优先引用,需要时才用指针"。
什么时候必须用指针?三个典型:可能为空(用 nullptr 表示"无")、要重新绑定、指向动态分配的对象(new 出来的东西、容器里的元素换位置)。
五、与本站主线衔接
- 引用作为函数参数(按引用传递、避免拷贝、
const引用)是下一篇的重头戏; - 右值引用与移动语义(
T&&)是 C++11 性能的核心,见移动语义与右值引用; - 引用的内存表示与寄存器/栈上怎么传,见专家层内存布局与 ABI(C 篇的指针模型 + C++ 对象布局)。
一句话总结
引用是变量的别名,必须初始化、不能换绑,底层常实现为自动解引用的指针;它没有空状态、语法像值、行为指原对象,所以"能用引用就用引用"是现代 C++ 的默认姿势,指针留给需要空值、换绑或动态内存的场景。
上一篇:默认参数 下一篇:值传递 vs 引用传递