引用的概念
引用的作用是为变量创建一个别名,使得通过这个别名可以直接操作原变量。引用的概念类似于Linux中的硬链接。任何对于引用的操作,实际上都是对原变量的操作。
示例
int a = 10;
int &r = a; // r 是 a 的引用
r = 20; // 修改 r 的值会影响 a
基本语法
引用使用 & 作为标识符
格式:数据类型 &引用名 = 引用的目标
例如:
int a =10;
int &r = a; //定义一个int类型的引用,引用变量a
引用的本质
引用的本质是 C++ 内部实现的 指针常量。因此,引用与指针有着相似之处,但它是更高层次的抽象,提供了更方便的操作方式。
定义引用时需要注意以下几点:
-
引用必须初始化:
定义引用时,必须为其指定一个初始化目标。
int a = 10;
int &r = a; // r 必须在定义时初始化
-
引用的类型与目标类型必须一致:
引用的类型必须与它所引用的变量类型保持一致。(继承和多态除外)
int a = 10;
int &r = a; // 类型一致
-
引用不可更改目标:
一旦引用绑定到一个变量上,不能再更改其引用的目标。
引用作为函数参数
作用
函数传参时,可以利用引用的技术让形参修饰实参
优点
可以简化指针修改实参
示例
#include "iostream"
using namespace std;
// 值传递
void func_swap_01(int val_1 , int val_2){
int temp = val_1;
val_1 = val_2;
val_2 = temp;
}
// 值传递
void func_swap_02(int *val_1 , int *val_2){
int temp = *val_1;
*val_1 = *val_2;
*val_2 = temp;
}
// 值传递
void func_swap_03(int &val_1 , int &val_2){
int temp = val_1;
val_1 = val_2;
val_2 = temp;
}
int main()
{
int val_1 = 10;
int val_2 = 20;
func_swap_01(val_1, val_2);
cout << "val_1 = " << val_1 << " val_2 = " << val_2 << endl;
func_swap_01(val_1, val_2);
cout << "val_1 = " << val_1 << " val_2 = " << val_2 << endl;
func_swap_01(val_1, val_2);
cout << "val_1 = " << val_1 << " val_2 = " << val_2 << endl;
}
示例结果
val_1 = 10 val_2 = 20
val_1 = 10 val_2 = 20
val_1 = 10 val_2 = 20
引用与指针
用法
#include <iostream>
#include <string>
#include <cstdlib>
using namespace std;
typedef struct Node {
int data;
struct Node* next;
}Node;
void create_node(Node * &p)
{
p = (Node*)malloc(sizeof(Node));
p->data = 100;
p->next = nullptr;
}
int main()
{
Node* list = nullptr;
create_node(list);
cout << list->data << endl;
}
引用与返回值
我们平时使用函数时,函数的返回值都是一个右值。
但是引用作为函数的返回值时,返回值是一个左值。
-
左值
既可以放在等号左边,也可以放在等号右边的值。
-
右值
只能放在等号右边的值。
引用作为函数的返回值,不能返回局部变量的引用,因为局部变量在函数调用结束时就被回收了。
可以返回全局变量的引用或者 static
修饰的局部变量的引用。
示例1
#include <iostream>
using namespace std;
// 返回静态局部变量的引用
int &my_add(const int &x, const int &y) {
static int temp = x + y; // 静态局部变量
return temp; // 返回 temp 的引用
}
// 返回全局变量 value 的引用
int value = 100;
int &func() {
return value; // 返回 value 的引用
}
int main() {
// 返回 temp 的引用
int &r1 = my_add(10, 20); // r1 绑定到 temp
cout << r1 << endl; // 输出 30
// 返回全局变量 value 的引用
int &r2 = func(); // r2 绑定到 value
cout << r2 << endl; // 输出 100
// 修改 value 的值
r2 = 200;
cout << value << endl; // 输出 200
// 通过 func() 修改 value
func() = 300;
cout << value << endl; // 输出 300
return 0;
}
示例2
#include <iostream>
int& getElement(int arr[], int index) {
return arr[index]; // 返回数组元素的引用
}
int main() {
int numbers[] = {10, 20, 30, 40, 50};
// 将getElement返回的引用作为左值
getElement(numbers, 2) = 100; // 修改索引为2的元素
// 输出修改后的数组
for (int i = 0; i < 5; ++i) {
std::cout << numbers[i] << " ";
}
std::cout << std::endl;
return 0;
}
引用与结构体
当结构体中包含引用时,定义结构体的对象时,必须对引用进行初始化。由于引用必须在创建时绑定到某个变量,因此不能延迟初始化。
1、引用结构:
2、结构体内部有引用:
初始化方式
MyStruct T1 = { .valur = 20 , .ref = val }; // 错误的写法,不能使用初始化列表的指定成员
MyStruct T1 = { 20 , val }; // 正确的写法,必须按照结构体成员顺序进行初始化
代码示例
#include <iostream>
#include <string>
#include <cstdlib>
using namespace std;
struct MyStruct {
int valur; // 普通成员
int &ref; // 引用成员,必须在初始化时绑定
};
int main() {
int val = 10; // 用于初始化引用的变量
MyStruct T1 = { 20, val }; // 初始化结构体,包括引用成员
val = 20; // 修改引用绑定的变量的值
cout << T1.ref << endl; // 输出 20,因为引用指向 val
}
引用与常量
当 const
修饰引用时,它被称为常引用。常引用的作用是禁止通过引用来修改其引用的目标变量。
作用:防止对引用目标的错误修改,保护数据的完整性。
#include <iostream>
#include <string>
#include <cstdlib>
using namespace std;
int func_Add(const int &val_1, const int &val_2) {
return val_1 + val_2;
}
int main() {
// 变量
int val = 10;
// 引用 常量引用
cosnt int &ref = val;
// 常量引用 引用变量
cout << "ref = " << ref << endl;
// 常量引用 作为参数
int val_1 = 80;
int val_2 = 80;
cout << "val_1 + val_2 = " << func_Add(val_1, val_2) << endl;
// 常用引用 引用常量
// int & ref_1 = 10; // 不使用常量引用是不能引用常量的
const int & ref_1 = 10;
const int val_3 = 50;
// int & ref_2 = val_3; // 不使用常量引用是不能引用const 所修饰的常量
const int & ref_2 = val_3;
// 常量引用 引用临时值
// int & ref_3 = val_1 + val_2; // 不使用常量引用是不能引用临时值的
const int & ref_3 = val_1 + val_2;
}
引用和指针的区别
要记,面试会问
1、引用必须初始化,指针可以不初始化。
2、引用不可以改变指向,指针可以。
3、不存在指向 NULL 的引用,指针可以指向 NULL。
4、指针在使用前需要检查合法性,引用不需要。