• C++入门2


    一、引用

    1.引用概念:

    引用(reference)就是C++对C语言的重要扩充。引用就是某一变量(目标)的一个别名,对引用的操作与对变量直接操作完全一样。引用的声明方法:类型标识符 &引用名=目标变量名。   我让林冲去招安和我让豹子头去招安的意思一样。

    注意: 用并没有开辟额外的空间,造成比必要的空间浪费。

    1.1引用要求

    • 引用在定义时必须初始化,且初始化指定后就不可修改,指针不必初始化,但可以改变指向
    • 一个变量可以有多个引用。
    • 引用一旦引用一个实体,再不能引用其他实体

    引用的具体运用:

    1. int main()
    2. {
    3. int a = 10;
    4. // int& b; // 1、引用在定义时必须初始化
    5. //此时b就是a的小名
    6. int& b = a; // 2、一个变量可以有多个引用
    7. int& c = a;
    8. int& d = c; // 也可以给别名取别名
    9. // 3、引用一旦引用一个实体,再不能引用其他实体,d不能在引用其他变量。
    10. ++a;
    11. int x = 10;
    12. b = x; // b是x的别名呢?还是x赋值给b呢?-->是赋值而非别名(调试看地址和原先别名的a是一样的,这和指针不同)
    13. return 0;
    14. }

     

    2.引用的真正场景

    • 1)做参数
      • ①输出型参数–>指针也能做,但引用相对舒服点。
      • ②大对象传参,提高效率–>没有拷贝,引用不开空间。
    • 2)做返回值
      • ①输出型返回对象,调用者可以修改返回对象。
      • ②减少拷贝,提高效率。

    2.1做参数

    做参数时和指针的应用有很大相似性。

    引用一般用作输出型参数

     这里的引用和指针作用基本一致,都能找到地址来改变数据。但是tmp为啥不用指针呢?因为a, b都不是地址,而是用的别名,但是也不是地址。

    2.2做返回值

    引用用作返回值是有条件的。当函数执行完作用后如果没有被销毁,那他可以用引用,如果被销毁了,就不能用作返回值了。因为当函数被销毁后地址就没了,而引用是一个别名,地址不变,但现在地址都没了还咋用。

    1. #define _CRT_SECURE_NO_WARNINGS 1
    2. #include
    3. #include
    4. using namespace std;
    5. int temp;
    6. int func1()
    7. {
    8. temp = 5;
    9. return temp;
    10. }
    11. int& func2()
    12. {
    13. temp = 8;
    14. return temp;
    15. }
    16. int main()
    17. {
    18. int a = 0, b = 0;
    19. // 1. 返回函数的普通类型
    20. a = func1();
    21. // 2. 返回函数的引用
    22. b = func2();
    23. // 3. 返回函数的引用去初始化一个新的引用
    24. int& c = func2();
    25. cout << "a = " << a << endl;
    26. cout << "b = " << b << endl;
    27. cout << "c = " << c << endl;
    28. return 0;
    29. }

    注意:一般传值引用是输入型参数,传址调用可以是输出型参数,也可以做输入型参数,做输入型参数时前面加const,表示只读不改。

    2.3传值返回和传引用返回

    2.31.传值返回:生成一个返回对象拷贝作为函数调用返回值。

    传值返回跟传值传参的情况很一致,它只是一份临时拷贝,不能修改本质。

    2.32传引用返回: 返回对象(n)的别名 

    传引用返回的正确运用:

    这个代码正确吗?为啥结果是对的?

    •  假如返回值取得是n的别名(即tmp),而tmp空间上的值就是n原来的数,
    • 但是出了Count函数,tmp就被销毁了,之所以还能打印出正确结果是侥幸,如果有的编译器销毁后n被置成随机值,tmp就会取到随机值。
    • 越界:好比申请房间,里面存一个变量,理论上除非别人非法入侵,变量是不会被修改的。但你把房间退了,里面还留着你的东西,就无法保障它不丢失,即使你下回去房间还没租给别人,所以东西被你找到了,也只能说是侥幸(因为换一个房间/编译器,是否还能保证找到就不好说了)。

     要想使用传引用返回就必须保证:返回值的别名出了作用域而未被销毁,还可以用作返回值。否则,这个别名并未改变它“本名”的地址,当原来的地址被销毁后,再去访问其地址也是胡闹。第一次可能闯上了,但第二次就一定不是了,不信看代码。

    printf也属一个函数调用,也需要建立栈帧

    栈帧的大小不一样,第一次可能没有覆盖Count的栈帧,但是第二次可能就覆盖了,所以打印的是随机值。

    理解:第一次printf调用后,就被销毁了n,第二次printf再回去找就找失败了。

    注意:不要弄混了传值,传址的区别;传值,传引用的区别。

    2.33.总结传值返回和传引用返回:

    • 出了函数作用域,返回对象就销毁了,那么一定不能用引用返回,一定要用传值返回
    • 下面的这个场景(static),出了作用域变量还在,才能使用引用返回

    3.权限的放大和缩小

    3.1权限的放大

     权限只能平移和缩小而不能放大。

    3.2权限的缩小

     3.3类型转换

     大家看这段代码,为啥rdd必须加const修饰呢?

    ii是int类型,rdd是double类型,当引用时会发生类型转换,但是ii还是int类型,只不过转换途中会产生一个临时变量。而rdd是这个临时变量的别名而临时变量具有常性,相当于const修饰过所以为了权限平移,加const。

    3.4const引用传参

    权限的放大和缩小只针对引用和指针,对于普通函数,根本没这个概念。

    •  对于这个函数,把a拷贝给n,n的改变不会影响a。

    但是我们要是用引用传参

     b,30根本传不过去,因为n是a的别名,又把b传过去,n改变了,所以a就改变了,所以会报错。

    所以如果使用引用传参,函数内如果不改变n,那么建议尽量用const引用传参

     3.5传引用返回和传引用传参

    • 传引用传参

    引用参数则是把形式参数转换成实参,换句话说就是在函数体里面实际操作的是参数的本身,即存放变量值的内存。

    • 传值传参

    当传入的是普通参数时,实际上函数体做了一个偷天换日的动作,是把普通参数的值,复制到有函数体生成的一个内存中。所以,在函数体中参数的值和传入时的值是一样的,但是它们内存地址是不一样的。

    • 传引用返回

    返回引用类型和传入引用参数类似,返回的值就是实际中函数体所操作的内存,所以,如果返回类型为引用时,不能将函数体中的局部变量返回(一般返回静态常量)局部变量的生命周期在函数体结束,当函数体结束时,局部变量也跟着结束。返回类型为引用时可以作为左值和右值

    • 传值返回

    返回普通类型和传入普通类型类似,函数体即将被返回的值也被偷天换日,将准备返回的值放入一个新生成的内存,最后再返回新生成的内存,这样就解决了函数体结束,局部变量也跟着结束的问题。返回类型为普通类型时,只能作为右值(=右边)来使用。

    4.指针和引用的区别

    1. 引用概念上定义一个变量的别名,指针存储一个变量地址
    2. 引用在定义时必须初始化,指针没有要求(指针不初始化其值为随机指向)
    3. 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何一个同类型实体
    4. 没有NULL引用,但有NULL指针
      • 空指针没有任何指向,删除无害,引用是别名,删除引用就删除真实对象
    5. 在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32位平台下占4个字节)
    6. 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小
    7. 有多级指针,但是没有多级引用
    8. 访问实体方式不同,指针需要显式解引用,引用编译器自己处理
    9. 引用比指针使用起来相对更安全
    10. 指针通过某个指针变量指向一个对象后,对它所指向的变量间接操作。程序中使用指针,程序的可读性差;而引用本身就是目标变量的别名,对引用的操作就是对目标变量的操作

    二、函数重载 

    1.什么是函数重载 

    函数重载是指在同一作用域内,可以有一组具有相同函数名,不同参数列表的函数,这组函数被称为重载函数。

    重载函数通常用来命名一组功能相似的函数,这样做减少了函数名的数量,避免了名字空间的污染,对于程序的可读性有很大的好处。

    函数重载的条件:

    这些同名函数的形参列表(参数个数 或 类型 或 顺序)必须不同。

    •  例如交换两个数,我们写一个形参是int的,但是传入的值是double型的这个函数就搞不了了,但是C语言不支持同名函数,而C++支持,也就是说把形参的类型转化一下就可以了。

     一定要注意函数重载不是函数重写!参数个数,参数顺序,参数类型至少有一个不同才算重载。

    仅仅修改函数的返回值是不构成重载的。

  • 相关阅读:
    大数据-之LibrA数据库系统告警处理(ALM-12047 网络读包错误率超过阈值)
    记一次应用接入第三方统一认证服务的过程,基于JWT和OAuth2.0
    【全网首发】【Python】Python控制parrot ARDrone 2.0无人机
    lwip --snmp概念篇
    Win11如何重命名音频设备
    【学习笔记】kafka学习二
    清除JavaWeb项目缓存的有效方式
    抓包工具fiddler
    二叉树的应用 | 幂集递归算法,汉诺塔递归算法,垂直输出二叉树,快速排序递归算法
    为什么要做知识管理
  • 原文地址:https://blog.csdn.net/bit_jie/article/details/126612574