• 【C++】C++入门(中)--引用


    目录

    一 引用概念

    二 引用特性

    三 常引用

    四 引用使用场景

    1 做参数

    2. 做返回值

    1 例一

    2 例二

    3 例三

    4 例四

    五 传值, 传引用效率比较

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

    七 引用和指针的区别


    一 引用概念

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

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

    1. int main()
    2. {
    3.        int a = 1;
    4.        int b = a;
    5.        int& c = a;
    6.        int& d = a;
    7.        int& e = c;
    8.        cout << &a << endl;
    9.        cout << &c << endl;
    10.        cout << &d << endl;
    11.        cout << &e << endl;
    12.        cout << &b << endl;
    13.        return 0;
    14. }

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

    二 引用特性

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

    2. 一个变量可以有多个引用

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

    1. int main()
    2. {
    3.        int a = 0;
    4.        // 引用必须初始化
    5.        // int& b; 这是错误的
    6.        int& c = a;
    7.        int d = 1;
    8.        // c变成d的别名?还是d赋值给c?--把d赋值给c
    9.        c = d;
    10.        // 一个对象可以有多个别名,可以别名继续取别名
    11.        int& e = a;
    12.        int& f = e;
    13.        return 0;
    14. }

    三 常引用

    1. void TestConstRef()
    2. {
    3.     const int a = 10;
    4.     //int& ra = a;   // 该语句编译时会出错,a为常量 权限不能放大
    5.     const int& ra = a;
    6.     // int& b = 10; // 该语句编译时会出错,b为常量
    7.     const int& b = 10;
    8.     double d = 12.34;
    9.     const double& rrd = d;//权限可以缩小
    10.     //int& rd = d; // 该语句编译时会出错,类型不同
    11.     const int& rd = d;//加了了const后 可以隐形类型提升
    12.     int i = 1;
    13.     double j = i;
    14.     const double& rj = i;
    15. }

     四 引用使用场景

    1 做参数

    1. // 传参数
    2. void Swap(int* left, int* right)
    3. {
    4.        int temp = *left;
    5.        *left = *right;
    6.        *right = temp;
    7. }
    8. void Swap(int& left, int& right)
    9. {
    10.        int temp = left;
    11.        left = right;
    12.        right = temp;
    13. }
    14. typedef struct SListNode
    15. {
    16.        struct SListNode* next;
    17.        int val;
    18. }SLTNode, * PSLTNode;
    19. //void SListPushBack(PSLTNode& phead, int x)
    20. void SListPushBack(SLTNode*& phead, int x)
    21. {
    22.        if (phead == NULL)
    23.        {
    24.               // ...
    25.               //phead = newnode;
    26.        }
    27.        else
    28.        {
    29.               // 找尾结点,再链接newnode
    30.               // tail->next = newnode;
    31.        }
    32. }
    33. int main()
    34. {
    35.        int a = 0, b = 2;
    36.        Swap(&a, &b);
    37.        Swap(a, b);
    38.        //PSLTNode plist = NULL;
    39.        SLTNode* plist = NULL;
    40.        SListPushBack(plist, 1);
    41.        SListPushBack(plist, 2);
    42.        SListPushBack(plist, 3);
    43.        return 0;
    44. }

    我们可以看到插入的时候我们就没有传地址了. 接收的就是她本身, 只是换取了一个名字

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

    2. 做返回值

    1 例一

    1. // 出了函数作用域,返回对象就销毁了,不能用引用返回,否则结果是不确定
    2. int& Count()
    3. {
    4.        int n = 0;
    5.        n++;
    6.        return n;
    7. }
    8. int main()
    9. {
    10.        int ret = Count();
    11.        cout << ret << endl;
    12.        cout << ret << endl;
    13.        return 0;
    14. }

     2 例二

    1. // 出了函数作用域,返回对象就销毁了,不能用引用返回,否则结果是不确定
    2. int& Add(int a, int b)
    3. {
    4.        int c = a + b;
    5.        return c;
    6. }
    7. int main()
    8. {
    9.        int& ret = Add(1, 2);//这里ret本质也是c的别名
    10.        cout << "Add(1, 2) is :" << ret << endl;
    11.        Add(3, 4);
    12.        cout << "Add(1, 2) is :" << ret << endl;
    13.        return 0;
    14. }

    3 例三

    1. int& Add(int a, int b)
    2. {
    3.        static int c = a + b;//静态变量 只接受一次初始值
    4.        return c;
    5. }
    6. int main()
    7. {
    8.        int& ret = Add(1, 2);
    9.        cout << "Add(1, 2) is :" << ret << endl;
    10.        Add(3, 4);
    11.        cout << "Add(1, 2) is :" << ret << endl;
    12.        return 0;
    13. }

    4 例四

    1. typedef struct SeqList
    2. {
    3.        int a[100];
    4.        int size;
    5. }SL;
    6. //void SLModify(SL* ps, int pos, int x)
    7. //{
    8. //     //...
    9. //     assert(ps);
    10. //     assert(pos < ps->size);
    11. //     ps->a[pos] = x;
    12. //}
    13. //引用做返回值:可以修改返回对象
    14. int& SLat(SL* ps, int pos)
    15. {
    16.        assert(ps);
    17.        assert(pos < ps->size);
    18.        
    19.        return ps->a[pos];
    20. }
    21. int main()
    22. {
    23.        SL s;
    24.        //...
    25.        SLat(&s, 3) = 10;
    26.        // 每个位置的值++
    27.        for (size_t i = 0; i < s.size; i++)
    28.        {
    29.               SLat(&s, i)++;
    30.        }
    31.        return 0;
    32. }

    这里SLat函数里的ps不是在此函数里定义的, 是在main函数定义传参过来的, 所以出了这个SLat函数, 返回值不会销毁, 所以可以引用返回.

    怎样判断?

    只要这个对象没有被定义在这个函数里, 即便函数执行结束了, 那么这个对象不会被销毁, 所以它的引用是存在的.

    五 传值, 传引用效率比较

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

    1. #include
    2. struct A { int a[10000]; };
    3. void TestFunc1(A a) {}
    4. void TestFunc2(A& a) {}
    5. void TestRefAndValue()
    6. {
    7.        A a;
    8.        // 以值作为函数参数
    9.        size_t begin1 = clock();
    10.        for (size_t i = 0; i < 10000; ++i)
    11.               TestFunc1(a);
    12.        size_t end1 = clock();
    13.        // 以引用作为函数参数
    14.        size_t begin2 = clock();
    15.        for (size_t i = 0; i < 10000; ++i)
    16.               TestFunc2(a);
    17.        size_t end2 = clock();
    18.        // 分别计算两个函数运行结束后的时间
    19.        cout << "TestFunc1(A)-time:" << end1 - begin1 << endl;
    20.        cout << "TestFunc2(A&)-time:" << end2 - begin2 << endl;
    21. }
    22. int main()
    23. {
    24.        TestRefAndValue();
    25. }

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

    1. #include
    2. struct A { int a[10000]; };
    3. A a;
    4. // 值返回
    5. A TestFunc1() { return a; }
    6. // 引用返回
    7. A& TestFunc2() { return a; }
    8. void TestReturnByRefOrValue()
    9. {
    10.        // 以值作为函数的返回值类型
    11.        size_t begin1 = clock();
    12.        for (size_t i = 0; i < 100000; ++i)
    13.               TestFunc1();
    14.        size_t end1 = clock();
    15.        // 以引用作为函数的返回值类型
    16.        size_t begin2 = clock();
    17.        for (size_t i = 0; i < 100000; ++i)
    18.               TestFunc2();
    19.        size_t end2 = clock();
    20.        // 计算两个函数运算完成之后的时间
    21.        cout << "TestFunc1 time:" << end1 - begin1 << endl;
    22.        cout << "TestFunc2 time:" << end2 - begin2 << endl;
    23. }
    24. int main()
    25. {
    26.        TestReturnByRefOrValue();
    27. }

    引用返回秒杀值返回

    七 引用和指针的区别

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

    指针通过某个指针变量指向一个对象后,对它所指向的变量间接操作。程序中使用指针,程序的可读性差;而引用本身就是目标变量的别名,对引用的操作就是对目标变量的操作

    1. int main()
    2. {
    3.        int a = 10;
    4.        // b是否开空间? -- > 没有
    5.        int& b = a;
    6.        // ptr开了空间
    7.        int* ptr = &a;
    8.        char ch = 'x';
    9.        char& r = ch;
    10.        cout << sizeof(r) << endl;
    11.        return 0;
    12. }

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

    引用表面好像是传值,其本质也是传地址,只是这个工作有编译器来做

    引用和指针的不同点:

    1. 引用概念上定义一个变量的别名,指针存储一个变量地址。

    2. 引用在定义时必须初始化,指针没有要求 引用一旦定义时初始化指定,就不能再修改,指针可以改变指向

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

    4. 没有NULL引用,但有NULL指针

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

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

    7. 有多级指针,但是没有多级引用

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

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

    本节讨论的主要就是引用, 引用的重要性很大, 可以说贯穿了整个C++过程, 只不过现在肯定感受不到的, 要在后面类和对象的学习中, 才能深刻感受到它的作用和魅力, 有些是指针不能替代的. 最后还是那句话, C基础不扎实的看这个会困难, 可以看我之前C语言的博客.

  • 相关阅读:
    MongoDB索引覆盖查询
    SpringBoot 开发 -- JWT 认证教程
    最新接口有关抖音,获取抖音分享口令url API
    靠着这份《Alibaba内部32W字面试手册》我已斩获15份offer
    亚马逊澳大利亚纽扣电池UL4200A认证标准和要求
    机器学习的第一节基本概念的相关学习
    SAP AIF BTI750
    微软Edge浏览器全解析
    猿创征文|Python迭代器、生成器、装饰器、函数闭包
    同一篇文章版权被同一公司反复起诉
  • 原文地址:https://blog.csdn.net/yf214wxy/article/details/134092244