在 C 语言中,使用指针(Pointer)可以间接获取、修改某个变量的值。
在 C++ 中,使用引用(Reference)可以起到跟指针类似的功能。
引用相当于是变量的别名,基本数据类型、枚举、结构体、类、指针、数组等都可以有引用。
对引用做计算,就是对引用所指向的变量做计算。
在定义的时候就必须初始化,一旦指向了某个变量,就不可以再改变,“从一而终”。
#includeusing namespace std; int main() { int age = 10; int height = 20; // 定义了一个age的引用,ref相当于是age的别名 int &ref = age; ref = 20; ref += 30; cout << age << endl; // 50 ref = height; ref = 11; cout << age << endl; // 11 cout << height << endl; // 20 getchar(); return 0; }
可以利用引用初始化另一个引用,相当于某个变量的多个别名。
#includeusing namespace std; int main() { int age = 10; // 定义了一个age的引用,ref相当于是age的别名 int& ref = age; int& ref1 = ref; int& ref2 = ref1; ref += 10; ref1 += 10; ref2 += 10; cout << age << endl; // 40 getchar(); return 0; }
不存在 “引用的引用”、“指向引用的指针”、“引用数组”。
引用存在的价值之一:比指针更安全、函数返回值可以被赋值。
#includeusing namespace std; void swap(int *v1, int *v2) { int tmp = *v1; *v1 = *v2; *v2 = tmp; } int main() { int a = 10; int b = 20; swap(&a, &b); cout << "a = " << a << ", b = " << b << endl; // a = 20, b = 10 getchar(); return 0; }
#includeusing namespace std; void swap(int &v1, int &v2) { int tmp = v1; v1 = v2; v2 = tmp; } int main() { int a = 10; int b = 20; swap(a, b); cout << "a = " << a << ", b = " << b << endl; // a = 20, b = 10 int c = 2; int d = 3; swap(c, d); cout << "c = " << c << ", d = " << d << endl; // c = 3, d = 2 getchar(); return 0; }
一个引用占用一个指针的大小。
#includeusing namespace std; struct Student { int age; }; int main() { cout << sizeof(Student) << endl; // x64(64bit): 4 // x86(32bit): 4 getchar(); return 0; }
#includeusing namespace std; struct Student { int *age; }; int main() { cout << sizeof(Student) << endl; // x64(64bit): 8 // x86(32bit): 4 getchar(); return 0; }
#includeusing namespace std; struct Student { int &age; }; int main() { cout << sizeof(Student) << endl; // x64(64bit): 8 // x86(32bit): 4 getchar(); return 0; }
引用的本质就是指针,只是编译器削弱了它的功能,所以引用就是弱化了的指针。
加断点,按 F5 进入调试,转到反汇编,不勾选“显示符号名”。
#includeusing namespace std; int main() { int age = 10; // *p就是age的别名 int *p = &age; *p = 30; getchar(); return 0; }
#includeusing namespace std; int main() { int age = 10; // ref就是age的别名 int &ref = age; ref = 30; getchar(); return 0; }
对比两图可以发现,ref 本质上就是指针,存储的就是 age 的地址值。
结构体的引用#include指针的引用using namespace std; struct Date { int year; int month; int day; }; int main() { Date d = { 2022, 1, 25 }; Date& ref = d; ref.year = 2023; cout << d.year << endl; // 2023 getchar(); return 0; }
#include常引用using namespace std; int main() { int age = 10; int *p = &age; int *&ref = p; *ref = 30; cout << age << endl; // 30 int height = 40; ref = &height; cout << *ref << endl; // 40 getchar(); return 0; }
引用可以被 const 修饰,这样就无法通过引用修改数据了,可以称为常引用。
const 必须写在 & 符号的左边,才能算是常引用。
#includeusing namespace std; int main() { int height = 20; int age = 10; // p1不能修改指向,但是可以利用p1间接修改所指向的变量 int* const p1 = &age; //p1 = &height; // 报错 *p1 = 30; cout << age << endl; // 30 // ref1不能修改指向,但是可以通过ref1间接修改所指向的变量 int & const ref1 = age; ref1 = 40; cout << age << endl; // 40 // p2可以修改指向,但是不可以利用p2间接修改所指向的变量 int const* p2 = &age; p2 = &height; //*p2 = 30; // 报错 // ref2不能修改指向,也不可以通过ref2间接修改所指向的变量 int const &ref2 = age; // 常引用 //ref2 = 40; // 报错 getchar(); return 0; }
const 引用可以指向临时数据(常量、表达式、函数返回值等)。
#includeusing namespace std; int main() { const int &ref = 30; getchar(); return 0; }
#includeusing namespace std; int main() { int a = 1; int b = 2; const int &ref = a + b; getchar(); return 0; }
#includeusing namespace std; int func() { return 8; } int main() { const int &ref = func(); getchar(); return 0; }
const 引用可以指向不同类型的数据。
#includeusing namespace std; int main() { int age = 10; const double &ref = age; getchar(); return 0; }
const 引用作为函数参数时,可以接受 const 和非 const 实参。
非 const 引用,只能接受非 const 实参。
const 引用可以跟非const引用构成重载。
const 引用作为函数参数时的规则也适用于const指针。
#includeusing namespace std; int sum(int &v1, int &v2) { cout << "sum(int &v1, int &v2)" << endl; return v1 + v2; } int sum(const int &v1, const int &v2) { cout << "sum(const int &v1, const int &v2)" << endl; return v1 + v2; } int main() { // 非const实参 int a = 10; int b = 20; sum(a, b); // const实参 const int c = 10; const int d = 20; sum(c, d); sum(10, 20); getchar(); return 0; }
当常引用指向了不同类型的数据时,会产生临时变量,即引用指向的并不是初始化时的那个变量。
#includeusing namespace std; int main() { int age = 10; const int &ref = age; age = 30; cout << age << endl; // 30 cout << ref << endl; // 30 getchar(); return 0; }
#include数组的引用using namespace std; int main() { int age = 10; const long &ref = age; age = 30; cout << age << endl; // 30 cout << ref << endl; // 10 getchar(); return 0; }
#includeusing namespace std; int main() { int array[3] = {1, 2, 3}; // 指针数组,数组里面可以存放3个int* int *arr1[3] = {array, array, array}; // 数组指针,用于指向数组的指针 int (*arr2)[3] = &array; // 数组的引用 int (&ref)[3] = array; ref[0] = 10; cout << array[0] << endl; // 10 getchar(); return 0; }
#includeusing namespace std; int main() { // 数组名arr其实是数组的地址,也是数组首元素的地址 // 数组名arr可以看做是指向数组首元素的指针(int *) int arr[] = {1, 2, 3}; cout << *(arr + 2) << endl; // 3 // 等价于arr[2] // 数组的引用 int (&ref)[3] = arr; cout << ref[2] << endl; // 3 // 数组的引用 int * const &refArr = arr; cout << refArr[2] << endl; // 3 getchar(); return 0; }



