一、引用的概念
引用是 C++ 对 C 语言的重要扩展。
它的作用是为变量创建一个别名,使得通过这个别名可以直接操作原变量。
引用的概念类似于 Linux 系统中的硬链接。任何对引用的操作,实际上都是对原变量的操作。
示例:
int a = 10;
int &r = a; // r 是 a 的引用
r = 20; // 修改 r 的值会影响 a
二、引用的基本语法
引用使用 &
作为标识符。
基本格式:
数据类型 &引用名 = 引用的目标;
int a = 10;
int &r = a; // 定义一个 int 类型的引用 r,引用变量 a
三、引用的本质
3.1 本质的介绍
引用的本质是 C++ 内部实现的 指针常量。因此,引用与指针有着相似之处,但它是更高层次的抽象,提供了更方便的操作方式。
定义引用时需要注意以下几点:
引用必须初始化:定义引用时,必须为其指定一个初始化目标。
int a = 10;
int &r = a; // r 必须在定义时初始化
引用的类型与目标类型必须一致:引用的类型必须与它所引用的变量类型保持一致。(继承和多态除外)
int a = 10;
int &r = a; // 类型一致
引用不可更改目标:一旦引用绑定到一个变量上,不能再更改其引用的目标。
int a = 10;
int &r = a;
r = 20; // 修改 r 的值,a 的值也会变为 20
3.2 示例代码
#include <iostream>
#include <string>
using namespace std;
int main(int argc, char const *argv[])
{
int val = 10 ;
int val_2 = 50 ;
int & ptr =val ;
ptr = val_2 ;
cout << ptr << endl;
return 0;
}
运行结果如下:
四、引用作为函数参数
4.1 作用
函数传参时,可以利用引用的技术让形参修饰实参
4.2 特点
可以简化指针修改实参
4.3 示例代码
#include <iostream>
#include <string>
using namespace std;
/*
使用引用传参的好处
以往使用指针 调用传参的时候 需要取地址
然后在函数内部 需要解指针
*/
void func_swap_1(int val_1, int val_2)
{
int temp = val_1;
val_1 = val_2;
val_2 = temp;
}
void func_swap_2(int *val_1, int *val_2)
{
int temp = *val_1;
*val_1 = *val_2;
*val_2 = temp;
}
void func_swap_3(int &val_1 ,int &val_2)
{
int temp = val_1;
val_1 = val_2;
val_2 = temp ;
}
int main(int argc, char const *argv[])
{
int val_1 = 80;
int val_2 = 60;
func_swap_1(val_1 ,val_2);
cout << val_1 << " " << val_2 << endl;
val_1 = 80 ;
val_2 = 60 ;
func_swap_2(&val_1 ,&val_2 );
cout << val_1 << " " << val_2 << endl;
val_1 = 80 ;
val_2 = 60 ;
func_swap_3(val_1 ,val_2 );
cout << val_1 << " " << val_2 << endl;
return 0;
}
运行结果如下:
五、引用与指针
用法如下:正常使用 变量没有太大区别
5.1示例代码
#include <iostream>
#include <string>
using namespace std;
int main(int argc, char const *argv[])
{
int val_1 = 10;
int val_2 = 20;
int * ptr_1 = &val_1;
int * ptr_2 = &val_2;
int * &ptr = ptr_1;
ptr =ptr_2;
cout << *ptr << endl;
return 0;
}
运行结果如下:
六、引用与返回值
6.1. 靠右原则
我们平时使用函数时,函数的返回值都是一个右值。
但是引用作为函数的返回值时,返回值是一个左值。
- 左值:既可以放在等号左边,也可以放在等号右边的值。
- 右值:只能放在等号右边的值。
引用作为函数的返回值,不能返回局部变量的引用,因为局部变量在函数调用结束时就被回
收了。
可以返回全局变量的引用或者
static
修饰的局部变量的引用。
6.2. 示例代码
/*
左值 既可以放在等号左边,也可以放在等号右边的值。
右值 只能放在等号右边的值。
左值
val1 = val2
val2 左值
右值
常量
表达式
在C++ 中 返回值的引用 是一个左值 可以被赋值的值
int & func(aaaaa);
func() = 10;
C++ 中的 引用返回值 不能是 局部变量
返回的引用变量 声明周期不能太短
可以用的返回
静态变量
全局变量
函数传参 传递的参数 需要是引用
*/
#include <iostream>
#include <string>
using namespace std;
// 使用静态的方式
int & Func_1()
{
static int val = 10;
return val;
}
// 全局
int num;
int & Func_2()
{
num = 80;
return num;
}
// 函数传参
int & Func_3(int & val)
{
return val;
}
int main(int argc, char const *argv[])
{
// 引用作为返回值 传递给引用 可以修改返回的值
int & val = Func_2();
val = 90;
cout << num << endl; // 打印全局
// 引用作为返回值 是左值
Func_2() = 123;
cout << num << endl; // 打印全局
// 引用的返回值是 参数
int arg = 10;
Func_3(arg) = 50;
cout << arg << endl; // 打印传递的参数
return 0;
}
运行结果如下:
七、引用与结构体
当结构体中包含引用时,定义结构体的对象时,必须对引用进行初始化。由于引用必须在创建时绑定到某个变量,因此不能延迟初始化。
7.1 初始化方式
MyStruct T1 = { .valur = 20 , .ref = val }; // 错误的写法,不能使用初始化列表的指定成员
MyStruct T1 = { 20 , val }; // 正确的写法,必须按照结构体成员顺序进行初始化
7.2 示例代码
引用结构体 和正常使用 引用变量没区别
但是 如何结构体内部成员有引用类型 则必须初始化
#include <iostream>
#include <string>
using namespace std;
typedef struct stu
{
string name ;
int & id;
}stu;
int main(int argc, char const *argv[])
{
int val = 10;
stu s1 = {"张三",val};
cout << s1.name << " " << s1.id << endl;
return 0;
}
运行结果如下:
八、引用与常量
8.1 定义
当 const
修饰引用时,它被称为常引用。常引用的作用是禁止通过引用来修改其引用的目标变量。
8.2 作用
防止对引用目标的错误修改,保护数据的完整性。
8.3 示例代码
/*
当 `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;
// 引用 常量引用
const 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;
return 0;
}
运行结果如下:
**拓展**
引用和指针的区别
1、引用必须初始化,指针可以不初始化。
2、引用不可以改变指向,指针可以。
3、不存在指向 NULL 的引用,指针可以指向 NULL。
4、指针在使用前需要检查合法性,引用不需要。