目录
什么是引用?
在C++中,引用是一个允许我们创建一个别名或者称之为变量的另一个名字的概念。通过引用,我们可以通过原始变量的别名来访问原始变量的值。引用提供了对原始变量的间接访问,我们可以通过引用来读取或修改原始变量的值。
引用的特点包括:
- 引用在声明时必须初始化,并且一旦初始化完成后,它将一直引用同一个变量,无法再引用其他变量。
- 引用在内部是通过指针来实现的,但其使用方式更类似于普通变量,因此可以简化指针的使用。
- 函数参数中使用引用可以避免对象的拷贝,提高运行效率。
- 引用常常用于函数返回值,允许函数返回引用指向的变量。
引用的基本使用
- 引用必须在定义时进行初始化,并且一旦与特定变量绑定,就无法更改绑定的对象。
- 引用不会占用额外的内存空间,因为它只是一个别名。
- 引用与原始变量具有同样的访问权限,可以对引用进行读取和写入操作。
- 引用在使用时和指针类似,但在语义上有所不同。引用本身不可变,不能被重新赋值为另一个对象。
- 语法:数据类型 &别名 = 原名
demo
int &b = a;将引用b与变量a绑定在一起。需要注意的是,引用本身不会分配额外的内存。
在内存的角度来看,变量a会在栈上分配一块内存用于存储值10。当你创建引用b时,它并不会占用额外的内存,而只是将b作为a的别名。实际上,b和a指向的是同一块内存地址。这意味着你可以通过b来操作变量a,例如对b进行修改,实际上是对a进行修改。 任何对b的操作都会被反映到a上,因为它们共享同一块内存
int a = 10;
int &b = a;
cout << "a = " << a << endl; // 10
cout << "b = " << b << endl; // 10
b = 100;
cout << "a = " << a << endl; // 100
cout << "b = " << b << endl; // 100
注意点
int c = 10;
//int &d; 错误,必须要初始化
int &d = c;
int e = 20;
d = e; // 赋值操作,而不是更改引用,当前会把 c d 都变为 20,所以引用在初始化后,不可以改变
cout << c << endl; // 20
cout << d << endl; // 20
cout << e << endl; // 20
引用做函数参数
#include <iostream>
using namespace std;
//1. 值传递
void mySwap01(int a, int b) {
int temp = a;
a = b;
b = temp;
}
//2. 地址传递
void mySwap02(int* a, int* b) {
int temp = *a;
*a = *b;
*b = temp;
}
//3. 引用传递
void mySwap03(int& a, int& b) { // a b分别是实参a b的别名,分别指向同一内存地址
int temp = a;
a = b;
b = temp;
}
int main() {
int a = 10;
int b = 20;
mySwap01(a, b);
cout << "a:" << a << " b:" << b << endl; // 10 20
mySwap02(&a, &b);
cout << "a:" << a << " b:" << b << endl; // 20 10
mySwap03(a, b);
cout << "a:" << a << " b:" << b << endl; // 10 20
return 0;
}
引用做函数返回值
不要返回局部变量引用
返回局部变量的引用是不安全的,因为在函数执行完毕后,局部变量a会被销毁,引用将会指向无效的内存地址。
int& test01() {
int a = 10; //局部变量
return a;
}
/* 不能返回局部变量的引用 */
int& ref = test01();
cout << "ref = " << ref << endl; // 第一次结果正确,是因为编译器做了保留
cout << "ref = " << ref << endl; // 第二次结果错误,因为a的内存已经释放
可以返回静态变量引用
返回静态变量引用(应该返回变量本身,而不是不加&符号:返回变量本身的数值)如果你不加 & 符号来定义函数返回类型作为引用,那么将返回局部变量的副本而不是引用。相当于返回了数值10,
比如:int &b = 10
所以:引用(&)是一种特殊的变量,它必须引用已存在的对象或变量。你不能将引用直接初始化为一个字面量或常数值。
int& test02() {
static int a = 20; // 静态变量,存放在全局区,全局区上的数据在程序结束后才会由系统释放
return a;
}
int& ref2 = test02();
cout << "ref2 = " << ref2 << endl; // 20
函数的返回值是引用,这个函数调用可以作为左值
如下,test02() = 1000; 其实是修改了 a 的值,将其修改为 1000,由于 ref2 是 a 的引用,所以对 a 的修改也会反映在 ref2 上,即 ref2 = 1000。
int& test02() {
static int a = 20; // 静态变量,存放在全局区,全局区上的数据在程序结束后才会由系统释放
return a;
}
int& ref2 = test02();
cout << "ref2 = " << ref2 << endl; // 20
/*
如果函数的返回值是引用,这个函数调用可以作为左值
*/
test02() = 1000; // 等同于 a == 1000 即 a的引用 == 1000
cout << "ref2 = " << ref2 << endl; // 1000
引用的本质
引用的本质在C++内部实现是一个指针常量
#include <iostream>
using namespace std;
/* 发现是引用,转换为 int *const p */
void func(int &p) {
p = 100; // p是引用,即 *p = 100
}
int main() {
int a = 10;
int &p = a; // 自动转换为 int *const p = &a; 即指针变量p指向的地址不可更改,但 *p 对指针的解引用可以更改
p = 20; // 内部发现p是引用,自动帮我们转换为:*p = 20;
cout << "a: " << a << endl;
cout << "p: " << p << endl;
func(a);
return 0;
}
常量的引用
#include <iostream>
using namespace std;
//引用使用的场景,通常用来修饰形参
void showValue(const int& v) {
//v += 10;
cout << v << endl; // const修饰,v引用指向的数据不可更改
}
int main() {
//int& ref = 10; 引用本身需要一个合法的内存空间(变量或对象,不应该是常量),因此这行错误
//加入const就可以了,编译器优化代码,int temp = 10; const int& ref = temp;
int A = 10;
const int &ref = A;
//ref = 100; //加入const后不可以修改变量
cout << ref << endl;
//函数中利用常量引用防止误操作修改实参
int a = 10;
showValue(a);
return 0;
}