浅谈C++引用的使用以及底层原理

1、引用概念

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

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

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

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

2、引用特性

  1. 引用在定义时必须初始化
  2. 一个变量可以有多个引用
  3. 引用一旦引用一个实体,再不能引用其他实体
void TestRef()
{
   int a = 10;
   // int& ra;   // 该条语句编译时会出错,因为它未初始化
   int& ra = a;
   int& rra = a;
   printf("%p %p %p\n", &a, &ra, &rra);  
}

3、常引用

意思就是const类型的引用也要const,不能const int 使用int引用。

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 Count()
{
    int n = 0;
    n++;

    return n;
}

int main()
{
    int a = 1;
    int& b = a;

    // 指针和引用,赋值/初始化 权限可以缩小,但是不能放大

    // 权限放大
    /*const int c = 2;
    int& d = c;

    const int* p1 = NULL;
    int* p2 = p1;*/

    // 权限保持
    const int c = 2;
    const int& d = c;

    const int* p1 = NULL;
    const int* p2 = p1;

    // 权限缩小
    int x = 1;
    const int& y = x;

    int* p3 = NULL;
    const int* p4 = p3;

    // 权限只适用于指针和引用,这个是可以的,n和m两个空间是独立的
    //const int m = 1;
    //int n = m;

    const int& ret = Count();//n是临时变量传值返回,不可被修改,加个const才行 

    
    //这部分听不懂,以后遇到重新学习  
    int i = 10;

    cout << (double)i << endl;

    double dd = i;

    const double& rd = i;

    return 0;
}

4、引用的使用场景

(1)做参数
void Swap(int& left, int& right)
{
   int temp = left;
   left = right;
   right = temp;
}
//使用了引用,函数里面改的就是实参,不需要用到取地址再解引用

函数在使用引用时,函数参数是引用int& i,实参也可以使i,因为他们是不同作用域的,可以同名。

形参的改变影响实参。 比如**phead的运用。

(2)做返回值

count 函数调用时,n的返回过程。

第一种是没有static,count的函数栈帧结束后,n的值传给临时变量,这个临时变量是在寄存器或者main函数里面开辟的,此时count函数栈帧被销毁还给操作系统,临时变量再赋值给main函数中的ret。

第二种是有static,其实和第一种差不多,只不过n是放在静态区,n一样要赋值给临时变量。

第三种是传引用返回,直接返回n,而不是传给临时变量。

image-20240310104611202.png

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

下面代码输出什么结果?为什么?

int& Add(int a, int b)
{
    int c = a + b;
    return c;
}
int main()
{
    int& ret = Add(1, 2);//这里的&去掉,ret依然是c的别名,函数结束后c依然还给了操作系统,ret一定是未知,当然有可能对,取决于第一次栈帧销毁时c的值。 
    Add(3, 4);
    cout << "Add(1, 2) is :"<< ret <<endl;//7
    return 0;
}
//上面是c是局部变量,函数结束后还给了操作系统,此时ret是c的引用别名,所以ret的值是未知的。

image-20240309101421894.png

注意:如果函数返回时,出了函数作用域,如果返回对象还在()引用返回,如果已经还给系统了,则必须使用传值返回。

技术前沿拓展

前端开发,你的认知不能仅局限于技术内,需要发散思维了解技术圈的前沿知识。细心的人会发现,开发内部工具的过程中,大量的页面、场景、组件等在不断重复,这种重复造轮子的工作,浪费工程师的大量时间。

介绍一款程序员都应该知道的软件JNPF快速开发平台,很多人都尝试用过它,它是功能的集大成者,任何信息化系统都可以基于它开发出来。

这是一个基于 Java Boot/.Net Core 构建的简单、跨平台快速开发框架。前后端封装了上千个常用类,方便扩展;集成了代码生成器,支持前后端业务代码生成,实现快速开发,提升工作效率;框架集成了表单、报表、图表、大屏等各种常用的 Demo 方便直接使用;后端框架支持 Vue2、Vue3。如果你有闲暇时间,可以做个知识拓展。

看完本文如果觉得有用,记得点个赞支持,收藏起来说不定哪天就用上啦~

  • 13
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值