【C++】C++ 引用详解 ① ( 变量的本质 - 引入 “ 引用 “ 概念 | 引用语法简介 | 引用做函数参数 | 复杂类型引用做函数参数 )

这篇具有很好参考价值的文章主要介绍了【C++】C++ 引用详解 ① ( 变量的本质 - 引入 “ 引用 “ 概念 | 引用语法简介 | 引用做函数参数 | 复杂类型引用做函数参数 )。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。





一、变量的本质 - 引入 " 引用 " 概念



" 引用 " 语法 是 C++ 语言中 特有的 , 在 C 语言中是没有 引用 这个概念的 ;


1、变量的本质 - 内存别名


分析 引用 之前 , 先回顾下 变量 :

在 【C 语言】变量本质 ( 变量概念 | 变量本质 - 内存空间别名 | 变量存储位置 - 代码区 | 变量三要素 ) 博客中 , 介绍了变量的本质 :

变量 的本质是 内存空间 的 " 别名 " , 简称 " 内存别名 " , 相当于 " 门牌号 " ;

C 语言 / C++ 语言 的 程序 , 通过 变量 来申请 内存空间 , 并为该 内存空间 命名 , 名称就是变量名 ;

下面的代码中 , 定义变量 a , 就是在 栈内存 中申请了 4 字节内存 , 这 4 字节连续内存的别名是 a , 为该变量赋值 10 , 就是将 10 存储到 4 字节内存中 ;

int a = 10;

通过 " 变量名称 " 可以使用 变量名 代表的 连续内存空间 , 之后使用变量 a 进行计算 , 就是 使用 变量 a 表示的 4 字节内存中的数据进行计算 ;


2、引入 " 引用 " 概念 - 已定义变量的内存别名


下面讨论下 , 上述 变量 a 是 4 字节连续内存空间的别名 , 那么 这段 4 字节的内存空间 只能有一个内存别名吗 ? 还是可以有多个内存别名 ?

答案是可以的 , 如果想要为 上述 4 字节内存空间再次 赋予 一个 " 内存别名 " , 就需要使用 " 引用 " 了 ;


" 引用 " 就是 已定义 变量 的 内存别名 ;

  • 第一次为 一块内存 赋予 别名 , 是 定义变量 的时候 ;
  • 第二次再为 该内存 赋予 别名 , 就是 获取该变量的 " 引用 " ;

3、" 引用 " 的优点


C++ 语言中的 引用 是特殊的变量 , 通过引用可以访问已经存在的变量 ;


使用 " 引用 " 的优点 :

  • 提高访问效率 : 向 函数 传递参数时 , 使用引用可以减少消耗 , 类似于传入指针 , 如果传入一个较大的数组 , 需要拷贝整个数组作为变量副本 , 拷贝会消耗很多性能 ;
  • 提高代码可读性 : 引用使用时 , 类似于 一级指针 , 使用引用期间 , 不需要 使用 取地址符 & 和 指针符号 * , 提高了代码可读性 和 可维护性 ;
  • 函数返回值 : 函数引用参数 可以作为 返回值使用 ;




二、引用语法简介




1、语法说明


" 引用 " 语法如下 :

类型& 引用名称 = 变量;

& 符号建议紧贴类型写 , 与 引用名称 使用空格隔开 ;

( 指针符号 * 建议也是紧贴 指针类型 , 与指针名称使用空格隔开 , 如 : int* p = NULL; )

引用 定义后 , 可以当做变量使用 ;

通过引用 , 可以操作变量 , 访问 , 修改 引用 , 变量也会进行相应修改 ;


使用引用作为函数参数时 ,

  • 传入的实参不需要使用取地址符获取 , 直接将变量传入函数即可 ;
  • 在函数中 访问引用 时 , 不需要使用指针 , 直接使用引用访问传入的变量 ;

代码示例 :

	// 定义变量 a , 变量本质是内存别名
	int a = 10;

	// 定义引用 b , 是变量 a 的别名
	int& b = a;

	// 通过引用修改变量的值
	b = 100;

引用是 C++ 的概念 , 在 C 语言中不能使用引用 ;

上述代码在 C 语言中实现 是完全不同的 , 下面是 上述代码在 C 语言中的实现 :

	// 定义变量 a , 变量本质是内存别名
	int a = 10;

	// 获取 变量 a 的地址 , 赋值给 指针常量 b 
	// 指针常量 是 常量 - 指针本身不能修改 , 常量指针 是 指针 - 指向常量的指针 
	// 左数右指 , const 在 指针 * 的右边 , 指针 是常量 , 指针的指向不能更改
	int* const b = &a;

	// 通过 指针常量 修改 指针指向的内存空间的值
	// 指针指向不能修改 , 指向的内存中的内容可以修改
	*b = 100;

在上述代码中 ,

  • 首先 , 获取 变量 a 的地址 , 赋值给 指针常量 b ;
    • 指针常量 是 常量 - 指针本身不能修改 ;
    • 常量指针 是 指针 - 指向常量的指针 ;
    • 左数右指 , const 在 指针 * 的右边 , 指针 是常量 , 指针的指向不能更改 ;
  • 然后 , 通过 指针常量 修改 指针指向的内存空间的值 ;
    • 指针指向的地址不能修改 ;
    • 指针指向的内存中的内容可以修改 ;

2、代码示例 - 引用的定义和使用


下面的代码中 , 引用 b 是 变量 a 的别名 , 通过 引用 b 可以访问 变量 a 的内存空间 ;

代码中同时打印 引用 b 和 变量 a , 都可以打印出 变量值 10 ;

修改 引用 b 的值 , 变量 a 的值也会被修改 ;


代码示例 :

// 包含 C++ 头文件
#include "iostream"

// 使用 std 标准命名空间
//		该命名空间中 , 定义了很多标准定义
using namespace std;

// 导入 C 头文件
#include <stdio.h>

int main()
{
	// 定义变量 a , 变量本质是内存别名
	int a = 10;

	// 定义引用 b , 是变量 a 的别名
	int& b = a;

	// 打印 变量 a 和 引用 b 的值
	printf("a = %d, b = %d\n", a, b);

	// 通过引用修改变量值
	b = 100;

	// 打印 变量 a 和 引用 b 的值
	printf("a = %d, b = %d\n", a, b);


	// 控制台暂停 , 按任意键继续向后执行
	//system("pause");
    return 0;
}

执行结果 :

a = 10, b = 10
a = 100, b = 100

【C++】C++ 引用详解 ① ( 变量的本质 - 引入 “ 引用 “ 概念 | 引用语法简介 | 引用做函数参数 | 复杂类型引用做函数参数 ),C++,c++,引用,变量,C语言,引用参数,原力计划





三、引用做函数参数




1、普通引用必须初始化 - 函数参数除外


普通的引用 , 必须要依附于某个变量 , 在定义 " 引用 " 时 , 必须进行初始化 , 否则就会报如下错误 :

引用 变量 x 需要初始值设定项

【C++】C++ 引用详解 ① ( 变量的本质 - 引入 “ 引用 “ 概念 | 引用语法简介 | 引用做函数参数 | 复杂类型引用做函数参数 ),C++,c++,引用,变量,C语言,引用参数,原力计划


这里有一种特殊情况 , 在声明时可以不进行初始化 ,

" 引用 " 做 函数 形参 时 , 可以不进行初始化 ;


使用 引用 作为 函数参数 , 与 一级指针 效果相同 , 并且用起来比较简单 , 不需要操作指针 ;

引用 比较符合 Java / C# 语言风格 , 不需要操作繁琐的指针 ;


定义两个变量 :

	// 定义变量 a , b ,  变量本质是内存别名
	int a = 10, b = 20;

写一个函数 , 交换这两个变量的值 ;


2、代码示例 - 使用普通变量作为参数 ( 无法实现变量交换 )


下面的代码中 , 定义的交换函数 , 传入的形参是普通变量 ;

参数是普通变量 , 实参就是变量的副本 , 变量的作用域仅限于函数内 , 无法传递到函数外部 , 外部的变量无法被改变 ;


代码示例 :

// 包含 C++ 头文件
#include "iostream"

// 使用 std 标准命名空间
//		该命名空间中 , 定义了很多标准定义
using namespace std;

// 导入 C 头文件
#include <stdio.h>

// 交换 a 和 b 的值
// 该函数无法实现交换 , 因为传入的实参只是副本
// 并不能真实的改变传入的值
void swap(int a, int b) 
{
	int c = 0;
	c = a;
	a = b;
	b = c;
}

int main()
{
	// 定义变量 a , b ,  变量本质是内存别名
	int a = 10, b = 20;

	// 打印 变量 a 和 引用 b 的值
	printf("a = %d, b = %d\n", a, b);

	// 传入变量副本 : 交换 a 和 b 的值 , 交换失败
	swap(a, b);
	// 打印 变量 a 和 引用 b 的值
	printf("a = %d, b = %d\n", a, b);


	// 控制台暂停 , 按任意键继续向后执行
	system("pause");
    return 0;
}

执行结果 :

a = 10, b = 20
a = 10, b = 20

【C++】C++ 引用详解 ① ( 变量的本质 - 引入 “ 引用 “ 概念 | 引用语法简介 | 引用做函数参数 | 复杂类型引用做函数参数 ),C++,c++,引用,变量,C语言,引用参数,原力计划


3、代码示例 - 使用指针变量作为参数 ( C 语言中实现变量交换的方法 )


在下面的代码中 , 使用 C 语言的方式实现了 变量交换函数 ;

函数参数接收 指针变量 作为 参数 , 传入的实参是变量的地址 ;

在函数内部 , 访问变量需要通过 指针 * 符号进行 ;

这样可以实现 外部变量 的数值交换 , 但是 使用 指针 * 进行操作 , 代码十分复杂繁琐 , 不易理解 ;


代码示例 :

// 包含 C++ 头文件
#include "iostream"

// 使用 std 标准命名空间
//		该命名空间中 , 定义了很多标准定义
using namespace std;

// 导入 C 头文件
#include <stdio.h>

// 交换 a 和 b 的值
// C 语言中可以使用该方法
void swap(int* a, int* b)
{
	int c = 0;
	c = *a;
	*a = *b;
	*b = c;
}

int main()
{
	// 定义变量 a , b ,  变量本质是内存别名
	int a = 10, b = 20;

	// 打印 变量 a 和 引用 b 的值
	printf("a = %d, b = %d\n", a, b);

	// 传入指针地址 : 交换 a 和 b 的值 , 交换成功
	swap(&a, &b);
	// 打印 变量 a 和 引用 b 的值
	printf("a = %d, b = %d\n", a, b);


	// 控制台暂停 , 按任意键继续向后执行
	system("pause");
    return 0;
}

执行结果 :

a = 10, b = 20
a = 20, b = 10

【C++】C++ 引用详解 ① ( 变量的本质 - 引入 “ 引用 “ 概念 | 引用语法简介 | 引用做函数参数 | 复杂类型引用做函数参数 ),C++,c++,引用,变量,C语言,引用参数,原力计划


4、代码示例 - 使用引用作为参数 ( C++ 语言中实现变量交换的方法 )


在下面的代码中 , 使用引用作为函数参数 , 也实现了变量交换 ;

C++ 中的引用使用非常简单 , 没有使用指针进行操作 ;

在使用引用时 , 可以看到 引用的效果 , 实际上等同于一级指针 ;

使用引用作为函数参数时 , 传入的实参不需要使用取地址符获取 , 直接将变量传入函数即可 , 在函数中获取引用的值时 , 不需要使用指针 , 直接使用引用访问传入的变量 ;


代码示例 :

// 包含 C++ 头文件
#include "iostream"

// 使用 std 标准命名空间
//		该命名空间中 , 定义了很多标准定义
using namespace std;

// 导入 C 头文件
#include <stdio.h>

// 交换 a 和 b 的值
// C++ 中推荐的方法
// 使用引用作为函数参数 
void swap(int& a, int& b)
{
	int c = 0;
	c = a;
	a = b;
	b = c;
}

int main()
{
	// 定义变量 a , b ,  变量本质是内存别名
	int a = 10, b = 20;

	// 打印 变量 a 和 引用 b 的值
	printf("a = %d, b = %d\n", a, b);

	// 传入引用本 : 交换 a 和 b 的值 , 交换成功
	swap(a, b);
	// 打印 变量 a 和 引用 b 的值
	printf("a = %d, b = %d\n", a, b);


	// 控制台暂停 , 按任意键继续向后执行
	system("pause");
    return 0;
}

执行结果 :

a = 10, b = 20
a = 20, b = 10

【C++】C++ 引用详解 ① ( 变量的本质 - 引入 “ 引用 “ 概念 | 引用语法简介 | 引用做函数参数 | 复杂类型引用做函数参数 ),C++,c++,引用,变量,C语言,引用参数,原力计划


5、代码示例 - 完整代码示例


完整代码示例 :

// 包含 C++ 头文件
#include "iostream"

// 使用 std 标准命名空间
//		该命名空间中 , 定义了很多标准定义
using namespace std;

// 导入 C 头文件
#include <stdio.h>

// 交换 a 和 b 的值
// 该函数无法实现交换 , 因为传入的实参只是副本
// 并不能真实的改变传入的值
void swap1(int a, int b) 
{
	int c = 0;
	c = a;
	a = b;
	b = c;
}

// 交换 a 和 b 的值
// C 语言中可以使用该方法
void swap2(int* a, int* b)
{
	int c = 0;
	c = *a;
	*a = *b;
	*b = c;
}

// 交换 a 和 b 的值
// C++ 中推荐的方法
void swap3(int& a, int& b)
{
	int c = 0;
	c = a;
	a = b;
	b = c;
}

int main()
{
	// 定义变量 a , b ,  变量本质是内存别名
	int a = 10, b = 20;

	// 打印 变量 a 和 引用 b 的值
	printf("a = %d, b = %d\n", a, b);

	// 传入变量副本 : 交换 a 和 b 的值 , 交换失败
	swap1(a, b);
	// 打印 变量 a 和 引用 b 的值
	printf("a = %d, b = %d\n", a, b);

	// 传入指针 : 交换 a 和 b 的值 , 交换成功
	swap2(&a, &b);
	// 打印 变量 a 和 引用 b 的值
	printf("a = %d, b = %d\n", a, b);

	// 传入引用 : 交换 a 和 b 的值 , 交换成功
	swap3(a, b);
	// 打印 变量 a 和 引用 b 的值
	printf("a = %d, b = %d\n", a, b);


	// 控制台暂停 , 按任意键继续向后执行
	//system("pause");
    return 0;
}

执行结果 :

a = 10, b = 20
a = 10, b = 20
a = 20, b = 10
a = 10, b = 20

【C++】C++ 引用详解 ① ( 变量的本质 - 引入 “ 引用 “ 概念 | 引用语法简介 | 引用做函数参数 | 复杂类型引用做函数参数 ),C++,c++,引用,变量,C语言,引用参数,原力计划





四、复杂类型引用做函数参数




1、复杂类型参数的三种传递方式


定义一个结构体类型 , 想要传递结构体对象到函数中 , 有三种方式 ;

// 定义一个结构体 
// C++ 中结构体就是类
struct Student
{
	char name[64];
	int age;
};

在栈内存中先创建该结构体对象 , 为该对象赋值 ;

	Student s;
	s.age = 18;

I 、传递结构体对象本身


第一种方式 , 直接传递结构体对象本身 ,

  • 函数传递 : 这种方式传递的是 结构体 对象的副本 , 需要拷贝对象然后将拷贝副本作为实参传递给函数 , 拷贝的过程非常消耗性能 ;
  • 参数访问 : 传入的参数在函数中正常访问 ,使用 . 访问结构体成员 ;
  • 参数修改 : 修改该参数 , 不会影响外部结构体对象的值 , 因为修改的是拷贝后的副本 ;
// 直接传入结构体类对象本身
void printStudent1(Student s)
{
	// 使用变量 , 直接使用 . 访问结构体成员
	cout << "printStudent1 开始执行 age : " << s.age << endl;
	s.age = 19;
}

II 、传递结构体指针


第二种方式 , 传递结构体 指针 ,

  • 函数传递 : 这种方式传递的是 结构体 指针 , 实际上是指针的副本 , 几乎不消耗性能 ;
  • 参数访问 : 传入的 指针 参数 在函数中 使用 -> 访问结构体成员 ;
  • 参数修改 : 通过指针 修改该参数 , 外部的结构体对象也会被修改 ;
// 传入结构体类对象指针
void printStudent2(Student* s)
{
	// 通过 问结构体指针 访问成员需要使用 -> 访问
	cout << "printStudent2 开始执行 age : " << s->age << endl;
	s->age = 20;
}

III 、传递结构体引用


第三种方式 , 传递结构体 引用 ,

  • 函数传递 : 这种方式传递的是 结构体 引用 , 引用只是变量的一个别名 , 几乎不消耗性能 ;
  • 参数访问 : 传入的 引用 参数 在函数中 使用 . 访问结构体成员 , 与变量用法一样 ;
  • 参数修改 : 通过指针 修改该参数 , 外部的结构体对象也会被修改 ;
// 传入结构体类对象指针
void printStudent2(Student* s)
{
	// 通过 问结构体指针 访问成员需要使用 -> 访问
	cout << "printStudent2 开始执行 age : " << s->age << endl;
	s->age = 20;
}

2、代码示例 - 使用三种传递方式传递参数


代码示例 :

// 包含 C++ 头文件
#include "iostream"

// 使用 std 标准命名空间
//		该命名空间中 , 定义了很多标准定义
using namespace std;

// 导入 C 头文件
#include <stdio.h>

// 定义一个结构体 
// C++ 中结构体就是类
struct Student
{
	char name[64];
	int age;
};

// 直接传入结构体类对象本身
void printStudent1(Student s)
{
	// 使用变量 , 直接使用 . 访问结构体成员
	cout << "printStudent1 开始执行 age : " << s.age << endl;
	s.age = 19;
}

// 传入结构体类对象指针
void printStudent2(Student* s)
{
	// 通过 问结构体指针 访问成员需要使用 -> 访问
	cout << "printStudent2 开始执行 age : " << s->age << endl;
	s->age = 20;
}

// 传入结构体类对象引用
void printStudent3(Student& s)
{
	// 使用 引用 跟普通变量用法相同, 不需要使用 -> 访问
	cout << "printStudent3 开始执行 age : " << s.age << endl;
	s.age = 21;
}

int main()
{
	Student s;
	s.age = 18;

	// 传入对象 消耗性能
	printStudent1(s);
	cout << "printStudent1 执行完毕 age : " << s.age << endl;

	// 传入指针 需要取地址
	printStudent2(&s);
	cout << "printStudent2 执行完毕 age : " << s.age << endl;

	// 传入引用 直接传入
	printStudent3(s);
	cout << "printStudent3 执行完毕 age : " << s.age << endl;


	// 控制台暂停 , 按任意键继续向后执行
	system("pause");
    return 0;
}

执行结果 :

printStudent1 开始执行 age : 18
printStudent1 执行完毕 age : 18
printStudent2 开始执行 age : 18
printStudent2 执行完毕 age : 20
printStudent3 开始执行 age : 20
printStudent3 执行完毕 age : 21
Press any key to continue . . .

【C++】C++ 引用详解 ① ( 变量的本质 - 引入 “ 引用 “ 概念 | 引用语法简介 | 引用做函数参数 | 复杂类型引用做函数参数 ),C++,c++,引用,变量,C语言,引用参数,原力计划文章来源地址https://www.toymoban.com/news/detail-672178.html

到了这里,关于【C++】C++ 引用详解 ① ( 变量的本质 - 引入 “ 引用 “ 概念 | 引用语法简介 | 引用做函数参数 | 复杂类型引用做函数参数 )的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C++的引用变量作为函数参数

    在C++的中新增一个特性:按引用传递变量,虽然与按传递变量的地址可以实现相同的结果,但引用有其独特的地方。 引用传递: 引用经常被用作函数参数,使得函数中的变量名成为调用程序中的变量的别名。 通过引用变量用作参数,函数将使用原始数据,而不是其副本。 举

    2023年04月14日
    浏览(26)
  • 【Linux】详解进程通信中信号量的本质&&同步和互斥的概念&&临界资源和临界区的概念

             访问资源在安全的前提下,具有一定的顺序性,就叫做同步 。在多道程序系统中,由于资源有限,进程或线程之间可能产生冲突。同步机制就是为了解决这些冲突,保证进程或线程之间能够按照既定的顺序访问共享资源。同步机制有助于避免竞态条件和死锁(

    2024年04月25日
    浏览(25)
  • C++ 默认参数与引用传递:语法、用法及示例

    在 C++ 中,函数参数可以拥有默认值。这意味着,在调用函数时,如果省略了某个参数,那么将使用为该参数指定的默认值。 默认参数值使用等号 = 符号进行设置,位于参数声明的类型之后。例如: 在这个例子中, country 是一个参数,它的默认值为 \\\"Norway\\\" 。这意味着,如果

    2024年04月15日
    浏览(37)
  • 【JavaScript】JavaScript 变量 ① ( JavaScript 变量概念 | 变量声明 | 变量类型 | 变量初始化 | ES6 简介 )

    JavaScript 变量 是用于 存储数据 的 容器 , 通过 变量名称 , 可以 获取 / 修改 变量 中的数据 ; 变量 的 本质 是 存放数据 的 一块内存空间 ; 在 JavaScript 中, 使用 var / let / const 来声明变量 , 每个变量都有一个 变量名 和 一个 变量值 ; JavaScript 变量声明 : var : 使用

    2024年03月15日
    浏览(39)
  • 【是C++,不是C艹】 引用的概念 | 引用的使用 | 引用与指针的区别

    💞💞 欢迎来到 Claffic 的博客 💞💞   👉  专栏: 《是C++,不是C艹》👈 前言: 前面带大家学习了函数重载等C++基础,这期继续C++基础的学习:引用。 注: 你最好是学完了C语言,并学过一些初阶的数据结构。 (没有目录) ヽ( ̄ω ̄( ̄ω ̄〃)ゝ  不知道大家听没听过这个梗

    2024年02月03日
    浏览(29)
  • Java和C++中的引用概念

    Java中的引用 在Java中,所有的对象都是通过引用来访问的。这些引用类似于C++中的指针。当你创建一个对象时,Java会在堆内存中为该对象分配空间,并返回一个指向该对象的引用。你可以使用这个引用来访问和操作对象。 例如: java Person person = new Person(\\\"John\\\"); 在这个例子中

    2024年02月05日
    浏览(28)
  • 「速通Shell」嵌点入线,Shell变量引用详解

    上一篇我们了解了Shell变量的定义和分类,对不同变量类型的特点和作用有了初步认识,今天我们将讲述Shell编程中变量该如何引用,将其融入到shell语句中,并进行相关操作。 Shell变量引用是指在Shell脚本中,使用变量名来获取该变量存储的值的过程。在Shell脚本中,使用变量

    2024年02月03日
    浏览(40)
  • 史上最详细的vite引入scss全局变量详解

    我们经常因为某些变量不能全局引入而头疼如麻,尤其是在做一些统一样式的时候,简直是噩梦,而且网上乱七八糟的文章很多很多,但是真正教你配置的没几个,因为很多都是复制过来的,有些人为了赶时间随便复制一下,这里将为你提供史上最详细的引入流程 第三步:创

    2024年02月16日
    浏览(26)
  • 【C++】C++ 引用详解 ⑦ ( 指针的引用 )

    指针的引用 效果 等同于 二级指针 , 因此这里先介绍 二级指针 ; 使用 二级指针 作为参数 , 可以实现如下功能 : 动态内存管理 : 借助二级指针 , 可以在函数中分配或释放内存 ; 如 : 创建一个动态数组或调整现有数组的大小 , 在函数中需要一个指向指针的指针作为参数 , 以便修

    2024年02月11日
    浏览(27)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包