C++引用分析实例与案例刨析及使用场景分析详解

简介: 多情况使用场景demo1地址和值都不可以修改 只读不可修改,防止误操作demo2指针常量,地址可变,值不可变 用于在函数体内给函数体外的变量更换别名,且别名只在函数体内有效demo3常量指针,地址不变,值可以变 正常的值传递,可以简化指针值传递的繁琐操作


引用

引用的基本使用

作用:给变量起别名

语法:数据类型 &别名 = 原名

示例:

intmain() {

   inta=10;

   int&b=a;

   cout<<"a = "<<a<<endl;

   cout<<"b = "<<b<<endl;

   b=100;

   cout<<"a = "<<a<<endl;

   cout<<"b = "<<b<<endl;

   system("pause");

   return0;

}

网络异常,图片无法展示
|

引用注意事项

  • 引用必须初始化
  • 引用在初始化后,不可以改变

示例:

intmain() {

   inta=10;

   intb=20;

   //int &c; //错误,引用必须初始化

   int&c=a; //一旦初始化后,就不可以更改

   c=b; //这是赋值操作,不是更改引用

   cout<<"a = "<<a<<endl;

   cout<<"b = "<<b<<endl;

   cout<<"c = "<<c<<endl;

   system("pause");

   return0;

}

引用做函数参数

作用:函数传参时,可以利用引用的技术让形参修饰实参

优点:可以简化指针修改实参

示例:

//1. 值传递

voidmySwap01(inta, intb) {

   inttemp=a;

   a=b;

   b=temp;

}

//2. 地址传递

voidmySwap02(int*a, int*b) {

   inttemp=*a;

   *a=*b;

   *b=temp;

}

//3. 引用传递

voidmySwap03(int&a, int&b) {

   inttemp=a;

   a=b;

   b=temp;

}

intmain() {

   inta=10;

   intb=20;

   mySwap01(a, b);

   cout<<"a:"<<a<<" b:"<<b<<endl;

   mySwap02(&a, &b);

   cout<<"a:"<<a<<" b:"<<b<<endl;

   mySwap03(a, b);

   cout<<"a:"<<a<<" b:"<<b<<endl;

   system("pause");

   return0;

}

总结:通过引用参数产生的效果同按地址传递是一样的。引用的语法更清楚简单

PS:值传递与地址传递的回顾:

值传递

  • 所谓值传递,就是函数调用时实参将数值传入给形参
  • 值传递时,==如果形参发生,并不会影响实参==

示例:

voidswap(intnum1, intnum2)

{

   cout<<"交换前:"<<endl;

   cout<<"num1 = "<<num1<<endl;

   cout<<"num2 = "<<num2<<endl;

   inttemp=num1;

   num1=num2;

   num2=temp;

   cout<<"交换后:"<<endl;

   cout<<"num1 = "<<num1<<endl;

   cout<<"num2 = "<<num2<<endl;

   //return ; 当函数声明时候,不需要返回值,可以不写return

}

intmain() {

   inta=10;

   intb=20;

   swap(a, b);

   cout<<"mian中的 a = "<<a<<endl;

   cout<<"mian中的 b = "<<b<<endl;

   system("pause");

   return0;

}

总结: 值传递时,形参是修饰不了实参的

地址传递

作用:利用指针作函数参数,可以修改实参的值

示例:

//值传递

voidswap1(inta ,intb)

{

   inttemp=a;

   a=b;

   b=temp;

}

//地址传递

voidswap2(int*p1, int*p2)

{

   inttemp=*p1;

   *p1=*p2;

   *p2=temp;

}

intmain() {

   inta=10;

   intb=20;

   swap1(a, b); // 值传递不会改变实参

   swap2(&a, &b); //地址传递会改变实参

   cout<<"a = "<<a<<endl;

   cout<<"b = "<<b<<endl;

   system("pause");

   return0;

}

总结:如果不想修改实参,就用值传递,如果想修改实参,就用地址传递

引用传递

可以修饰实参。本质:接收(int *const a ,int * const b) 传入(&a,&b),编译器自动把识别引用所以使用引用时只传入(a,b)即可。

网络异常,图片无法展示
|

注意:别名可以和原名相同

引用做函数返回值

分析

作用:引用是可以作为函数的返回值存在的

注意:不要返回局部变量引用

用法:函数调用作为左值

示例

//返回局部变量引用

int&test01() {

   inta=10; //局部变量

   returna;

}

//返回静态变量引用

int&test02() {

   staticinta=20;

   returna;

}

intmain() {

   //不能返回局部变量的引用

   int&ref=test01();

   cout<<"ref = "<<ref<<endl;//第一次结果正确,编译器做了保留

   cout<<"ref = "<<ref<<endl;//第二次可能会输出乱码

   //如果函数做左值,那么必须返回引用

   int&ref2=test02();

   cout<<"ref2 = "<<ref2<<endl;

   cout<<"ref2 = "<<ref2<<endl;

   test02() =1000;

   cout<<"ref2 = "<<ref2<<endl;

   cout<<"ref2 = "<<ref2<<endl;

   system("pause");

   return0;

}

解析:返回值类型后面加上and符int&相当于用引用的方式返回数据。如下图例子返回的是a的一个别名,再用一个别名ref去接收函数返回的别名,最终ref是a的一个别名。

网络异常,图片无法展示
|

网络异常,图片无法展示
|

上图结果:第二次输出就是乱码了,编译器不再保留改函数栈区数据a的地址!

网络异常,图片无法展示
|

但是加上static关键字后数据性质就不一样了,静态变量存贮与静态区,程序运行后释放!

网络异常,图片无法展示
|

可以作为左值就是可以进行和变量一样的操作,编译器不会报错。

PS:上图案例刨析

案例分析:函数返回值不能返回局部变量的引用 类比于 不能返回局部变量的地址

旧知识回顾:不能返回局部变量的地址

栈区:

由编译器自动分配释放, 存放函数的参数值,局部变量等

注意事项:不要返回局部变量的地址,栈区开辟的数据由编译器自动释放

示例:

int*func()

{

   inta=10;

   return&a;

}

intmain() {

   int*p=func();

   cout<<*p<<endl;//第一次编译器可能会保留

   cout<<*p<<endl;//第二次直接会报错!取决于编译器。

   system("pause");

   return0;

}

引用的本质

分析

本质:引用的本质在c++内部实现是一个指针常量(指针指向不可改).

讲解示例:

//发现是引用,转换为 int* const ref = &a;

voidfunc(int&ref){

   ref=100; // ref是引用,转换为*ref = 100

}

intmain(){

   inta=10;

   

   //自动转换为 int* const ref = &a; 指针常量是指针指向不可改,也说明为什么引用不可更改

   int&ref=a;

   ref=20; //内部发现ref是引用,自动帮我们转换为: *ref = 20;

   

   cout<<"a:"<<a<<endl;

   cout<<"ref:"<<ref<<endl;

   

   func(a);

   return0;

}

结论:C++推荐用引用技术,因为语法方便,引用本质是指针常量,但是所有的指针操作编译器都帮我们做了

图析

网络异常,图片无法展示
|

int * const ref = &a;指针常量,地址不可以改变,值可以改变,即引用的地址不可以改变,即引用不可更改

旧知回顾

引用注意事项

  • 引用必须初始化
  • 引用在初始化后,不可以改变

常量引用

作用:常量引用主要用来修饰形参,防止误操作

在函数形参列表中,可以加==const修饰形参==,防止形参改变实参

示例:

//引用使用的场景,通常用来修饰形参

void showValue(const int& v) {

//v += 10;

cout << v << endl;

}


int main() {


//int& ref = 10;  引用本身需要一个合法的内存空间,因此这行错误

//加入const就可以了,编译器优化代码,int temp = 10; const int& ref = temp;

const int& ref = 10;


//ref = 100;  //加入const后不可以修改变量

cout << ref << endl;


//函数中利用常量引用防止误操作修改实参

int a = 10;

showValue(a);


system("pause");


return 0;

}

加入const表示只读不可修改,防止误操作

实例刨析

网络异常,图片无法展示
|

既然引用的实质是指针,那我们可以利用指针的性质来进行一些实验性操作,见上图的demo1-demo3

多情况使用场景

demo1地址和值都不可以修改

只读不可修改,防止误操作

demo2指针常量,地址可变,值不可变

用于在函数体内给函数体外的变量更换别名,且别名只在函数体内有效

demo3常量指针,地址不变,值可以变

正常的值传递,可以简化指针值传递的繁琐操作

目录
相关文章
|
2月前
|
程序员 编译器 C++
【C++核心】C++内存分区模型分析
这篇文章详细解释了C++程序执行时内存的四个区域:代码区、全局区、栈区和堆区,以及如何在这些区域中分配和释放内存。
51 2
|
8天前
|
Ubuntu Linux Shell
C++ 之 perf+火焰图分析与调试
【11月更文挑战第6天】在遇到一些内存异常的时候,经常这部分的代码是很难去进行分析的,最近了解到Perf这个神器,这里也展开介绍一下如何使用Perf以及如何去画火焰图。
|
1月前
|
存储 算法 搜索推荐
对二叉堆的简单分析,c和c++的简单实现
这篇文章提供了对二叉堆数据结构的简单分析,并展示了如何在C和C++中实现最小堆,包括初始化、插入元素、删除最小元素和打印堆的函数,以及一个示例程序来演示这些操作。
34 19
|
1月前
|
Ubuntu Linux Shell
C++ 之 perf+火焰图分析与调试
【10月更文挑战第8天】在遇到一些内存异常的时候,经常这部分的代码是很难去进行分析的,最近了解到Perf这个神器,这里也展开介绍一下如何使用Perf以及如何去画火焰图。
|
2月前
|
编译器 C++
【C++核心】指针和引用案例详解
这篇文章详细讲解了C++中指针和引用的概念、使用场景和操作技巧,包括指针的定义、指针与数组、指针与函数的关系,以及引用的基本使用、注意事项和作为函数参数和返回值的用法。
37 3
|
2月前
|
C++
【C++案例】一个项目掌握C++基础-通讯录管理系统
这篇文章通过一个通讯录管理系统的C++项目案例,详细介绍了如何使用C++实现添加、显示、删除、查找、修改和清空联系人等功能。
42 3
|
2月前
|
Ubuntu Linux Shell
C++ 之 perf+火焰图分析与调试
简介 在遇到一些内存异常的时候,经常这部分的代码是很难去进行分析的,最近了解到Perf这个神器,这里也展开介绍一下如何使用Perf以及如何去画火焰图。 1. Perf 基础 1.1 Perf 简介 perf是Linux下的一款性能分析工具,能够进行函数级与指令级的热点查找。利用perf剖析程序性能时,需要指定当前测试的性能时间。性能事件是指在处理器或操作系统中发生的,可能影响到程序性能的硬件事件或软件事件 1.2 Perf的安装 ubuntu 18.04: sudo apt install linux-tools-common linux-tools-4.15.0-106-gen
|
2月前
|
JavaScript 前端开发 测试技术
一个google Test文件C++语言案例
这篇文章我们来介绍一下真正的C++语言如何用GTest来实现单元测试。
20 0
|
4月前
|
存储 安全 C++
浅析C++的指针与引用
虽然指针和引用在C++中都用于间接数据访问,但它们各自拥有独特的特性和应用场景。选择使用指针还是引用,主要取决于程序的具体需求,如是否需要动态内存管理,是否希望变量可以重新指向其他对象等。理解这二者的区别,将有助于开发高效、安全的C++程序。
32 3
|
4月前
|
安全 编译器 C++
C++一分钟之-模板元编程实例:类型 traits
【7月更文挑战第15天】C++的模板元编程利用编译时计算提升性能,类型traits是其中的关键,用于查询和修改类型信息。文章探讨了如何使用和避免过度复杂化、误用模板特化及依赖特定编译器的问题。示例展示了`is_same`类型trait的实现,用于检查类型相等。通过`add_pointer`和`remove_reference`等traits,可以构建更复杂的类型转换逻辑。类型traits增强了代码效率和安全性,是深入C++编程的必备工具。
74 11