返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C++引用如何使用
  • 285
分享到

C++引用如何使用

2023-06-30 14:06:06 285人浏览 独家记忆
摘要

这篇文章主要介绍“c++引用如何使用”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“C++引用如何使用”文章能帮助大家解决问题。一. 引用的概念引用不是新定义一个变量,而是给已存在变量取了一个别名,编

这篇文章主要介绍“c++引用如何使用”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“C++引用如何使用”文章能帮助大家解决问题。

    一. 引用的概念

    引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。

    类型& 引用变量名(对象名) = 引用实体;

    如下:

    void TestRef(){     int a = 10;     int& ra = a;//<====定义引用类型     printf("%p\n", &a);     printf("%p\n", &ra);}

    注意:引用类型必须和引用实体是同种类型的

    二. 引用特性

    引用在定义时必须初始化

    一个变量可以有多个引用

    引用一旦引用一个实体,再不能引用其他实体

    如下:

    void TestRef(){     int a = 10;     int a2 = 20;     //a的多个引用     int& b = a;     int& c = a;     int& d = b;     int& ra;//该条语句编译时会出错,未初始化     int &ra = a2;//报错,引用了其他实体     printf("%p %p %p %p\n", &a, &b, &c, &d); }

    C++引用如何使用

    三. 常引用

    void TestConstRef(){     const int a = 10;     //int& ra = a; // 该语句编译时会出错,a为常量     const int& ra = a;     // int& b = 10; // 该语句编译时会出错,b为常量     const int& b = 10;     double d = 12.34;     //int& rd = d; // 该语句编译时会出错,类型不同     const int& rd = d;     //int& c = 100; // 该语句编译时会出错,常量是只读的     const int& c = 100;}

    注意:

    引用取别名原则:对原引用变量,读写权限只能缩小,不能放大

    const int a = 10;

    int& ra = a;

    编译不通过,因为放大了权限,原引用本来是只读,但是引用以后却变成了可读可写

    int& b = 10;

    const int& b = 10;

    编译可以通过,因为缩小了权限,原引用本来是可读可写,引用后变成了只读

    double d = 12.34;

    int& rd = d;

    编译不通过,这里比较特殊,看起来是因为类型不同而报错,其实不然,报错是因为权限放大了,为什么?

    int类型要引用double类型,double类型转化到int类型属于隐式类型转换会舍弃小数位,隐式类型转换会产生临时变量,double类型到int类型会创建一个临时变量存储double变成了int类型的值,这里需要注意,这个临时变量具有常性是只读的,rd其实是引用了这个临时变量,因为临时变量是只读的,引用了临时变量的rd也应该是只读的,所以这就是为什么const int& rd = d 可以编译通过。

    int& c = 100;

    编译通过,因为常量本来就是只读的,不加const代表引用后变成了可读可写,权限放大。

    四. 使用场景

    1. 做参数

    void Swap(int& left, int& right){     int temp = left;     left = right;     right = temp;}
    • 输出型参数

    • 减少拷贝,提高效率

    2. 做返回值

    int& Count(){     static int n = 0;     n++;     // ...     return n;}

    减少拷贝

    (传值返回需要拷贝数据,传引用返回直接返回变量的别名)

    3. 做返回值需要注意的问题

    首先,我们要知道当函数返回一个值时,会生成一个临时变量,而函数的返回类型就是这个临时变量的类型

    int Add(int a, int b){    return a + b;}int Count(){    static int n = 0;    n++;    return n;}int main(){    int temp = Add(2, 3);    int tmp = Count();    return 0;}

    以上代码将a+b(n)的值赋值给临时变量,临时变量再赋值给temp(tmp),为什么要设置这个临时变量?

    其实很简单,在这个代码里是会有问题的,出了函数作用域a+b的值就已经被销毁了,需要一个临时变量去储存这个返回值,再去访问那块空间是非法的,而被static修饰的n由于它的生命周期变长了,即使出了函数也不会被销毁

    那么问题来了,以下代码是正确的吗?

    int& Add(int a, int b){     int c = a + b;     return c;}int main(){     int& ret = Add(1, 2);     return 0;}

    很明显是有问题的!这里将c的引用返回 ,而一旦出了函数c就被销毁了,这块空间也被操作系统收回,再将c的引用赋值给ret就变成了非法访问了,就变成了由引用造成的野指针

    由上面的问题可以衍生出以下代码:

    这里的ret是什么?

    int& Add(int a, int b){     int c = a + b;     return c;}int main(){     int& ret = Add(1, 2);     Add(3, 4);     cout << "Add(1, 2) is :"<< ret <<endl;     return 0;}

    很明显是7,ret是c的引用,由于出了函数以后这块空间的使用权还给了操作系统,由于第二次函数调用仍然是在第一次函数调用的空间进行栈帧的建立,因为ret的地址(ret的地址就是之前那块临时变量的地址)还是之前那个地址,所以由于第二次返回c时建立的临时变量已经变成了7,所以ret也变成了7

    但是一定会是7吗?其实不然,我们知道这块空间的使用权还给了操作系统,这块空间也有可能会被其他程序使用了,导致数值变成了不确定性,因为这里是直接马上又调用了这个函数,所以会是7,所以,其实正确答案应该是随机值才对

    看下面这个代码就是典型的例子:

    int& Add(int a, int b){     int c = a + b;     return c;}int main(){     int& ret = Add(1, 2);     Add(3, 4);     cout << "Add(1, 2) is :"<< ret <<endl;     cout << "Add(1, 2) is :"<< ret <<endl;     return 0;}

    这里的输出语句其实也是调用了函数,由上面可知第一个是7,那么第二个呢?随机值!因为进行了第一次输出后其实也是进行了函数调用,函数调用会建立栈帧,在上一个输出建立的栈帧处重新建立了栈帧,函数调用前需要先传参,由于上一个输出语句销毁完栈帧以后ret地址处的值被覆盖成随机值,在第二次输出语句中此时就会把这个随机值作为参数传过去给函数,导致输出了随机值,所以传引用返回不是所有情况都可以使用的,像一开始加上了static关键字之类的才可以返回,因为n的生命周期变长了,出了函数作用域没有被销毁,取值都是去静态区取数据。

    结论:如果函数返回时,出了函数作用域,如果返回对象还未还给系统,则可以使用引用返回,如果已经还给系统了,则必须使用传值返回。

    五. 传值传引用效率对比

    以值作为参数或者返回值类型,在传参和返回期间,函数不会直接传递实参或者将变量本身直接返回,而是传递实参或者返回变量的一份临时的拷贝,因此用值作为参数或者返回值类型,效率是非常低下的,尤其是当参数或者返回值类型非常大时,效率就更低。

    1. 值和引用传参时的效率比较

    #include <time.h>struct A { int a[10000]; };void TestFunc1(A a) {}void TestFunc2(A& a) {}void TestFunc3(A* a) {}void TestRefAndValue(){A a;// 以值作为函数参数size_t begin1 = clock();for (size_t i = 0; i < 10000; ++i)TestFunc1(a);size_t end1 = clock();// 以引用作为函数参数size_t begin2 = clock();for (size_t i = 0; i < 10000; ++i)TestFunc2(a);size_t end2 = clock();// 以指针作为参数size_t begin3 = clock();for (size_t i = 0; i < 10000; ++i)TestFunc3(&a);size_t end3 = clock();// 分别计算两个函数运行结束后的时间cout << "TestFunc1(A)-time:" << end1 - begin1 << endl;cout << "TestFunc2(A&)-time:" << end2 - begin2 << endl;cout << "TestFunc2(A&)-time:" << end3 - begin3 << endl;}

    C++引用如何使用

    2. 值和引用的作为返回值类型的性能比较

    #include <time.h>struct A{ int a[10000]; };A a;// 值返回A TestFunc1() { return a;}// 引用返回A& TestFunc2(){ return a;}void TestReturnByRefOrValue(){     // 以值作为函数的返回值类型     size_t begin1 = clock();     for (size_t i = 0; i < 100000; ++i)     TestFunc1();     size_t end1 = clock();     // 以引用作为函数的返回值类型     size_t begin2 = clock();     for (size_t i = 0; i < 100000; ++i)     TestFunc2();     size_t end2 = clock();     // 计算两个函数运算完成之后的时间     cout << "TestFunc1 time:" << end1 - begin1 << endl;     cout << "TestFunc2 time:" << end2 - begin2 << endl;}

    C++引用如何使用

    通过上述代码的比较,发现传值和指针在作为传参以及返回值类型上效率相差很大。

    六. 引用和指针

    在语法概念上引用就是一个别名,没有独立空间,和其引用实体共用同一块空间。

    int main(){     int a = 10;     int& ra = a;     cout<<"&a = "<<&a<<endl;     cout<<"&ra = "<<&ra<<endl;     return 0;}

    在底层实现上实际是有空间的,因为引用是按照指针方式来实现的。

    int main(){     int a = 10;     int& ra = a;     ra = 20;     int* pa = &a;     *pa = 20;     return 0;}

    我们来看下引用和指针的汇编代码对比:

    引用和指针的不同点:

    • 引用在定义时必须初始化,指针没有要求(建议初始化)

    • 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何一个同类型实体

    • 没有NULL引用,但有NULL指针

    • 在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32位平台下占 4个字节)

    • 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小

    • 有多级指针,但是没有多级引用

    • 访问实体方式不同,指针需要显式解引用,引用编译器自己处理

    • 引用比指针使用起来相对更安全

    引用和指针的相同点:

    虽然从语法角度来看引用是别名没有额外开空间,但是底层角度来看他们是一样的。

    什么是底层角度呢?就是通过编译器处理的结果来看,以下是指针和引用经编译器处理后的结果

    C++引用如何使用

    C++引用如何使用

    我们会发现汇编指令是一致的,这就说明了从底层角度看这两个实现方式是一样的

    关于“C++引用如何使用”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识,可以关注编程网其他教程频道,小编每天都会为大家更新不同的知识点。

    --结束END--

    本文标题: C++引用如何使用

    本文链接: https://lsjlt.com/news/329503.html(转载时请注明来源链接)

    有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

    猜你喜欢
    • C++引用如何使用
      这篇文章主要介绍“C++引用如何使用”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“C++引用如何使用”文章能帮助大家解决问题。一. 引用的概念引用不是新定义一个变量,而是给已存在变量取了一个别名,编...
      99+
      2023-06-30
    • C++引用方法如何使用
      这篇文章主要讲解了“C++引用方法如何使用”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“C++引用方法如何使用”吧!1.什么是引用引用可以看作是一个已经定义的变量的别名,其作为变量别名而存在...
      99+
      2023-06-30
    • C#中如何使用引用类型
      C#中如何使用引用类型,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。首先,让我们来看一看值类型(value)(在 C# 中用结构声明)。class t...
      99+
      2023-06-17
    • C#中如何使用索引器
      本篇文章给大家分享的是有关C#中如何使用索引器,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。1、索引器的定义C#中的类成员可以是任意类型,包括数组和集合。当一个类包含了数组和集...
      99+
      2023-06-17
    • 如何使用 C++ 引用和指针传参?
      c++++ 中引用和指针都是传递函数参数的方法,但有区别。引用是变量的别名,修改引用会修改原始变量,而指针存储变量的地址,修改指针值不会修改原始变量。在选择使用引用还是指针时,需要考虑是...
      99+
      2024-04-13
      指针 引用 c++
    • C++的引用如何应用
      这篇文章主要讲解了“C++的引用如何应用”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“C++的引用如何应用”吧!在C++中,引用就是一个变量的别名,它需要用另一个变量或对象来初始化自身。引用...
      99+
      2023-06-17
    • C语言单引号与双引号如何使用
      今天小编给大家分享一下C语言单引号与双引号如何使用的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。一、单引号和双引号C语言中的...
      99+
      2023-06-30
    • 如何使用 C++ 函数中的引用参数
      引用参数直接指向传递给函数的变量,提供效率、可修改性和安全性。具体来说,引用参数可以提高效率(避免复制)、允许函数修改调用者中的变量,并消除悬引用风险。语法为在类型名前加 &am...
      99+
      2024-04-19
      c++ 引用参数
    • C++右值如何引用
      本篇内容介绍了“C++右值如何引用”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!1.左值和右值在我们之前的文章当中,介绍的都是左值引用。C+...
      99+
      2023-06-22
    • C#中如何使用值类型和引用类型
      C#中如何使用值类型和引用类型,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。1。变量:变量是指在程序的运行过程中随时可以发生变化的量。语法:数据类型 变量名2。常量:也称常数,...
      99+
      2023-06-17
    • 如何在C#中使用RulesEngine规则引擎
      今天就跟大家聊聊有关如何在C#中使用RulesEngine规则引擎,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。简介RulesEngine是微软推出的规则引擎,规则引擎在很多企业开发...
      99+
      2023-06-06
    • C++中如何引用常量
      C++中如何引用常量,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。如果是对一个常量进行引用,则编译器首先建立一个临时变量,然后将该常量的值置入临时变量中,对该引用的操作就是...
      99+
      2023-06-17
    • 如何使用HTML引用js
      这篇文章主要介绍了如何使用HTML引用js,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。   一、JavaScript脚本语言的特性  ...
      99+
      2024-04-02
    • 如何通过C#引用传递
      这篇文章主要介绍“如何通过C#引用传递”,在日常操作中,相信很多人在如何通过C#引用传递问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”如何通过C#引用传递”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!C#...
      99+
      2023-06-17
    • c#中using如何引用文件
      在C#中,使用using关键字是用来引用命名空间的,而不是用来引用文件。如果想要引用一个文件,可以使用System.IO命名空间中的...
      99+
      2024-04-08
      c#
    • 如何使用mysql索引
      这篇文章主要为大家展示了如何使用mysql索引,内容简而易懂,希望大家可以学习一下,学习完之后肯定会有收获的,下面让小编带大家一起来看看吧。什么是索引:索引可以帮助快速查找数据而基本上索引都要求唯一(有些不...
      99+
      2024-04-02
    • mysql索引如何使用
      小编给大家分享一下mysql索引如何使用,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!一、索引是什么1.索引简介索引其实是以文件...
      99+
      2024-04-02
    • MySQL如何使用索引
      这篇文章给大家分享的是有关MySQL如何使用索引的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。MYSQL的事务配置项 innodb_flush_log_at_trx...
      99+
      2024-04-02
    • C++引用类型怎么使用
      这篇文章主要介绍“C++引用类型怎么使用”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“C++引用类型怎么使用”文章能帮助大家解决问题。一、C++中的引用类型思考:如何在被调函数中修改主调函数中定义的...
      99+
      2023-07-02
    • C++中引用的使用总结
      1引用的定义 引用时C++对C的一个重要的扩充,引用的作用是给变量起一个别名。 例如: int a; int &b=a;//声明b是a的引用 经过以上的声明,b就成为了a的别...
      99+
      2022-11-15
      引用 C++
    软考高级职称资格查询
    编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
    • 官方手机版

    • 微信公众号

    • 商务合作