【C++】C++入门详解 II【深入浅出 C++入门 这一篇文章就够了】(上)

简介: 【C++】C++入门详解 II【深入浅出 C++入门 这一篇文章就够了】

七、引用

(一)引用 概念

(1)引用 概念

引用不是新定义一个变量而是给已存在变量取了一个别名

编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间

就好比 鲁迅 和 周树人 是同一个人。



(2)引用 使用

引用就是取别名;

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

【★☆★ 注意:引用类型 必须和 引用实体同种类型 的】

在这里插入代码片



★☆(3)引用 特性

  1. 引用在定义时必须初始化

  2. 一个变量可以有多个引用
    别名也可以再取别名

也可对常量进行别名


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

    定义了是一个实体的别名,就不能再改变成其他实体的别名了 。
  • C++中无法通过=符号,将引用一个实体得到的别名,更改为另一实体的别名。
  • 但Java中可以 通过=符号,改变别名的引用的方向。

所以,别名不能完全替代指针,更多的是 别名指针配合使用



(4)常引用

//常引用
int main(){
   const int a = 10;
   int& b = a;
   return 0;
}

大家可以去自己的编译器下运行一下这段代码,看看会出现什么问题

详解



  • const 修饰:
  1. 可做 const修饰的 变量的别名 (权限可平移)
  2. 也可做 非const修饰的 变量的别名(权限可缩小)
  • 指针也同样存在权限放大缩小的问题:
    const + 指针 也不能传给 非const的指针 去保存。(在const修饰下,还存在可修改的可能,这是不合法的)
  • 总结:
    权限可平移,可缩小,但不能放大 。

这里则是 定义了另外一个变量空间b,将a的值赋值给b,对值的拷贝,对a的权限没有影响,所以是合法的。



(二)引用的 实际应用 及 其意义

也正是因为别名和它引用的变量 共用同一块内存空间这一特性,所以 取别名就跟把地址传过去一样,改变的内存空间都是同一块。为后文,做参数时,大大提高了写代码的效率【请看下文】



☆(1)做参数 —— &形参取别名 可做到 形参的改变可影响实参


☆★ 1.1 传值、传引用效率比较

  • 传值
    以值作为参数或者返回值类型,在传参和返回期间函数不会直接传递实参或者将变量本身直接返回,而是传递实参或者返回变量的一份临时的拷贝

因此用值 作为参数或者返回值类型,效率是非常低下的,尤其是当 参数或者返回值类型 非常大 时,效率就更低

  • 传引用 = 传指针(且还会比传指针更方便)
    正是因为 别名和它引用的变量 共用同一块内存空间这一特性,所以 取别名就跟把地址传过去一样,改变的内存空间都是同一块
    所以,对 传过来的参数取别名(作为形参) = 在 解引用* 实参的地址,直接对实参的地址进行操作,不需要再拷贝内容了 。



1.2 传值、引用传参 性能测试对比



(2)做返回值

问题一:下面代码输出什么结果?为什么?

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

答案是 3,7;


解析



★ 讨论:传引用返回值时 的函数调用完后栈帧销毁,收回空间使用权后是否还能找到数据 问题

  • 传值返回中,传回去的是 n值的拷贝
  • 而在传引用返回中,则是 相当于 引用n取了个别名tmp(别名与实体 共用同一块空间,地址相同),把tmp传回去,相当于就是把n传回去(因为地址相同)。

☆ 但会出现类似野指针的问题,因为函数调用完了,函数开辟的栈帧就被销毁了,空间的使用权被操作系统收回,但空间还在,操作系统继续运行程序时,再重新将这块空间进行分配,重复利用

所以 返回的是多少取决于:

  1. 编译器是否在销毁栈帧时清理n的空间
  2. 以及,是否在空间使用权收回后,分配给下一个程序,是否有程序运行产生的数据将其要返回的原空间 变量n储存的数值 覆盖



函数栈帧的调用与销毁 不懂的同学建议去看一下这篇文章,了解其底层原理,能帮助我们更好的掌握知识,串联知识。】




改进:用 static 进行修饰,出了作用域,对象还在(合法化),才能引用返回

  • 问题二:那要是把条件改为 static int c = a + b;和 结果又会发生什么变化呢
int& Add(int a, int b)
{
    static int c = a + b;        //局部静态变量,只会被初始化一次
    return c;
}
int main()
{
    int& ret = Add(1, 2);
    cout << "Add(1, 2) is :"<< ret <<endl;
    Add(3, 4);
    cout << "Add(1, 2) is :"<< ret <<endl;
    return 0;
}
  • 问题三:static int c; c = a + b; 值又是多少呢?
int& Add(int a, int b)
{
    static int c;
    c = a + b;
    return c;
}
int main()
{
    int& ret = Add(1, 2);
    cout << "Add(1, 2) is :"<< ret <<endl;
    Add(3, 4);
    cout << "Add(1, 2) is :"<< ret <<endl;
    return 0;
}

目录
相关文章
|
1月前
|
安全 编译器 程序员
【C++初阶】C++简单入门
【C++初阶】C++简单入门
|
2月前
|
程序员 C++
C++模板元编程入门
【7月更文挑战第9天】C++模板元编程是一项强大而复杂的技术,它允许程序员在编译时进行复杂的计算和操作,从而提高了程序的性能和灵活性。然而,模板元编程的复杂性和抽象性也使其难以掌握和应用。通过本文的介绍,希望能够帮助你初步了解C++模板元编程的基本概念和技术要点,为进一步深入学习和应用打下坚实的基础。在实际开发中,合理运用模板元编程技术,可以极大地提升程序的性能和可维护性。
|
16天前
|
编译器 Linux C语言
C++基础入门
C++基础入门
|
1月前
|
安全 编译器 C++
C++入门 | 函数重载、引用、内联函数
C++入门 | 函数重载、引用、内联函数
25 5
|
1月前
|
存储 安全 编译器
C++入门 | auto关键字、范围for、指针空值nullptr
C++入门 | auto关键字、范围for、指针空值nullptr
49 4
|
1月前
|
编译器 C语言 C++
C++入门 | 命名空间、输入输出、缺省参数
C++入门 | 命名空间、输入输出、缺省参数
33 4
|
1月前
|
编译器 程序员 C语言
C++入门
C++入门
31 5
|
1月前
|
安全 编译器 C语言
C++入门-数组
C++入门-数组
|
1月前
|
存储 编译器 程序员
C++从遗忘到入门
本文主要面向的是曾经学过、了解过C++的同学,旨在帮助这些同学唤醒C++的记忆,提升下自身的技术储备。如果之前完全没接触过C++,也可以整体了解下这门语言。
|
1月前
|
存储 Serverless C++
【C++航海王:追寻罗杰的编程之路】一篇文章带你认识哈希
【C++航海王:追寻罗杰的编程之路】一篇文章带你认识哈希
11 0