C++入门编程 ---- 助你更好理解C++的奥妙(二)

简介: C++入门编程 ---- 助你更好理解C++的奥妙(二)

引用的一般使用场景:

分为:做 性参 和 返回值


做形参:

就好像是我们前面写的 那两个swap函数一样 再来就是:

大家都知道我们的C语言的 scanf("%d", &a ); 那这里的取地址操作就是因为我们的scanf函数回去我们缓冲区里面区提取数据 如果直接给给 a 这样是肯定不行的 这里的 &a 就是scanf函数的参数 我们传 a 的地址进去 在里面对a的地址解引用改变a 这样对a进行的改变才会影响到我们传进去的参数(实参)

那现在有了我们的引用操作还需要这样嘛 


我们利用引用传参 的效率是比 我们直接传值 的效率要高的

       因为 我们以值作为参数或者返回类型的时候,在开始的传参 和 返回期间 函数不会直接传递实参或者直接把返回值直接返回 而是会传递实参的临时拷贝或者是返回变量的临时拷贝 如果这样的话 那我们的效率可想而知是很低下的 并且如果我们参数或者返回值类型很大时 效率会更低 就好比是 结构体类型


做返回值:

大家看这样的结果是什么

int test()
{
    static int n=0;
    n++;
    return n;
}
int main()
{
    cout<<test()<<endl;
    cout<<test()<<endl;
    cout<<test()<<endl;
}


答案: 1  2  3  这里大家要注意一个点就是我们的 static 语句是只执行一次的 之所以提这个我们在了解引用做返回值之前 我们要理清楚值返回的特性

27505b9b81984d51b5062c27d6776120.png

那有什么办法可以证明 临时变量 的存在呢? 大家看下面的代码:

int test()
{
    int n=0;
    n++;
    return n;
}
int main()
{
    int& a=test();
}

大家觉得上面这段代码 编译器能编译通过嘛? 大家试过应该知道这里是会报错的 正确的代码应该是这样的:

int test()
{
    int n=0;
    n++;
    return n;
}
int main()
{
   const int& a=test();
}

这样我们的编译器才不会报错 也就暗示我们传返回值回来的时候 产生的临时变量是常性的(也就是被const修饰的)

那如果是这样呢?

int& test()
{
    int n=0;
    n++;
    return n;
}
int main()
{
    int& a=test();
}

我们这里使用传引用返回又是什么意思呢 ?

       我们既然返回的是一个引用 那这个引用是谁的引用呢 我们这里写得是 return n 不就是返回n的引用嘛 那既然我返回的是 n 的引用(返回n的别名) 我们用 int& a 来接收 这样我们不就得 a不就是 返回来的别名的别名了嘛  意思就是我们得 a 是n的别名的别名  那这样想我们的a不就是n的别名了嘛

我们来验证一下吧:

77f085001ce9404c9575b5174c659cd4.png

 这样不就表明我们的 a是n的别名了嘛   那大家现在觉得我们的传引用返回和传值返回的区别是什么


很显然 我们的传值返回 是会产生一个临时变量的 这个临时变量具有常性 而我们的传引用返回不会 它会直接返回返回的变量的别名

所以: 我们的传引用返回是不需要拷贝的

     但是我们上面的代码还是有问题的 如果大家有了解过栈帧的创建与销毁的话 大家就知道我们的一个函数在执行它的功能后就会返回上一层函数 与此同时这个函数里面为临时变量分配的空间就会还给操作系统 那我们这里写的代码肯定也是会那样的 所以当我们返回引用后 a的地址 就不能再去访问了 因为这块空间因为 n 所在函数栈帧的销毁而返回给操作系统了  此时如果在访问 就是越界的问题了

b5ff1acacbec488fb5aa032a883699ac.png

我们第一次去调用 没问题 而后面两次出现了随机数的情况  是因为我们第一次使用 cout 从流里面读取数据时 我们首先是要先传参的 参数就是我们的  a  而这个时候我们去访问那片空间值还是正确的 因为这片空间还没有被清理 修改 或者 覆盖 那么此时访问这片空间得到的值就还时正确的 但是后面我们传完参之后 调用 cout (这个也是一个函数) 也会有一片自己的空间 此时这篇空间就继续使用test函数用完后的空间  这是这里的空间就被覆盖使用了 里面的数据也就跟随着修改了所以后面两次调用也就时随机的值了


总结:如果函数返回时,出了函数的作用域,如果返回对象还在(还没还给我们的操作系统),那么就可以使用引用返回,如果已经返回给系统了,那么就必须使用传值返回 

目录
相关文章
|
1月前
|
存储 C++ UED
【实战指南】4步实现C++插件化编程,轻松实现功能定制与扩展
本文介绍了如何通过四步实现C++插件化编程,实现功能定制与扩展。主要内容包括引言、概述、需求分析、设计方案、详细设计、验证和总结。通过动态加载功能模块,实现软件的高度灵活性和可扩展性,支持快速定制和市场变化响应。具体步骤涉及配置文件构建、模块编译、动态库入口实现和主程序加载。验证部分展示了模块加载成功的日志和配置信息。总结中强调了插件化编程的优势及其在多个方面的应用。
227 64
|
1月前
|
编译器 C++
C++入门12——详解多态1
C++入门12——详解多态1
38 2
C++入门12——详解多态1
|
30天前
|
安全 程序员 编译器
【实战经验】17个C++编程常见错误及其解决方案
想必不少程序员都有类似的经历:辛苦敲完项目代码,内心满是对作品品质的自信,然而当静态扫描工具登场时,却揭示出诸多隐藏的警告问题。为了让自己的编程之路更加顺畅,也为了持续精进技艺,我想借此机会汇总分享那些常被我们无意间忽视却又导致警告的编程小细节,以此作为对未来的自我警示和提升。
85 5
|
1月前
|
C++
C++入门13——详解多态2
C++入门13——详解多态2
79 1
|
1月前
|
存储 安全 编译器
【C++打怪之路Lv1】-- 入门二级
【C++打怪之路Lv1】-- 入门二级
23 0
|
1月前
|
自然语言处理 编译器 C语言
【C++打怪之路Lv1】-- C++开篇(入门)
【C++打怪之路Lv1】-- C++开篇(入门)
24 0
|
1月前
|
分布式计算 Java 编译器
【C++入门(下)】—— 我与C++的不解之缘(二)
【C++入门(下)】—— 我与C++的不解之缘(二)
|
1月前
|
编译器 Linux C语言
【C++入门(上)】—— 我与C++的不解之缘(一)
【C++入门(上)】—— 我与C++的不解之缘(一)
|
1月前
|
编译器 C++
C++入门11——详解C++继承(菱形继承与虚拟继承)-2
C++入门11——详解C++继承(菱形继承与虚拟继承)-2
29 0
|
1月前
|
程序员 C++
C++入门11——详解C++继承(菱形继承与虚拟继承)-1
C++入门11——详解C++继承(菱形继承与虚拟继承)-1
32 0