• 引用的本质分析


    1. 引用的定义

    C++新增加了引用的概念:

    • 引用可以看作一个已定义变量的别名
    • 引用的语法Type &name = var;
    int a = 4;
    int &b = a;  //b为a的别名
    b = 5;       //操作b就是操作a
    

    2. 引用的本质

    • 引用在C++中的内部实现是一个常量指针Type &name <==> Type *const name
    • C++编译器在编译过程中使用常量指针作为引用的内部实现,因此引用所占用的内存大小和指针相同
    • 从使用的角度,引用只是一个别名,C++为了实用性而隐藏了引用的存储空间这一细节
    #include <cstdio>
    
    struct TRef
    {
        char &r;
    };
    
    int main(int argc, char *argv[])
    {
        char c = 'c';
        char &rc = c;
        TRef ref = { c };
    
        printf("sizeof(rc) = %d
    ", sizeof(rc));
        printf("sizeof(TRef) = %d
    ", sizeof(TRef)); 
        printf("sizeof(ref) = %d
    ", sizeof(ref)); 
        printf("sizeof(ref.r) = %d
    ", sizeof(ref.r));   
    
        /*sizeof(type &)的大小,就是type类型的大小*/ 
        printf("sizeof(char &) = %d
    ", sizeof(char &));  
        printf("sizeof(int &) = %d
    ", sizeof(int &));
        printf("sizeof(double &) = %d
    ", sizeof(double &));
    
        return 0;
    }
    

    #include <stdio.h>
    
    struct TRef
    {
        char *before;
        char &ref;
        char *after;
    };
    
    int main(int argc, char *argv[])
    {
        char a = 'a';
        char &b = a;
        char c = 'c';
    
        TRef r = {&a, b, &c};
    
        printf("sizeof(r) = %d
    ", sizeof(r));
        printf("sizeof(r.before) = %d
    ", sizeof(r.before));
        printf("sizeof(r.after) = %d
    ", sizeof(r.after));
        printf("&r.before = %p
    ", &r.before);
        printf("&r.after = %p
    ", &r.after);
    
        return 0;
    }
    

    3. 引用的意义

    • C++中的引用作为变量别名而存在,旨在大多数的情况下代替指针
    • 引用可以满足绝大多数需要使用指针的场合
    • 引用可以避开由于指针操作不当而带来的内存错误
    • 引用相对于指针来说具有更好的可读性和实用性

    注意:由于引用的内部实现为指针,因此函数不能返回非静态局部变量的引用

    #include <stdio.h>
    
    int &demo()
    {
        int d = 0;
    
        printf("demo: d = %d
    ", d);
    
        return d;
    }
    
    int &func()
    {
        static int s = 0;
    
        printf("func: s = %d
    ", s);
    
        return s;
    }
    
    int main(int argc, char *argv[])
    {
        int &rd = demo();
        int &rs = func();
    
        printf("
    ");
        printf("main: rd = %d
    ", rd);
        printf("main: rs = %d
    ", rs);
        printf("
    ");
    
        rd = 10;
        rs = 11;
    
        demo();
        func();
    
        printf("
    ");
        printf("main: rd = %d
    ", rd);
        printf("main: rs = %d
    ", rs);
        printf("
    ");
    
        return 0;
    }
    

    4. 特殊的引用—const引用

    • 在C++中可以声明const引用const Type &name = var
    • 可以使用const常量、变量、字面值常量对const引用初始化
    • 不管使用何种方式初始化,const引用都将产生一个只读变量
    • 当使用字面值常量对const引用初始化时,C++编译器会为常量值分配内存空间,并将引用作为这段内存空间的别名

    const引用类型 VS 初始化变量类型

    • 类型相同,const引用的就是初始化变量
    • 类型不同,const引用的不是初始化变量,而是初始化变量的临时对象

    注意:const只是修饰符,不代表类型,也就是说,const int和int是相同类型。

    #include <stdio.h>
    
    int main()
    {
        const int a = 3;
        int b = 4;
        char c = 'c';
    
        const int &ra = a;
        const int &rb = b;
        const int &rc = c;
        const int &rd = 1;
    
        int *p1 = (int *)&ra;
        int *p2 = (int *)&rb;
        int *p3 = (int *)&rc;
        int *p4 = (int *)&rd;
    
        *p1 = 5;
        *p2 = 6;
        *p3 = 7;
        *p4 = 8;
    
        printf("ra = %d
    ", ra);
        printf("rb = %d
    ", rb);
        printf("rc = %d
    ", rc);
        printf("rd = %d
    ", rd);
    
        printf("
    ");
    
        printf("b = %d
    ", b);  //b的类型和rb相同,rb引用的就是b,所以改变rb的值,b也跟着一起改变
        printf("c = %c
    ", c);  //c的类型和rc不同,rb引用的是c的临时对象,所以改变rc的值,c不受影响
    
        return 0;
    }
    

    5. 引用和指针的关系

    指针 引用
    指针是一个变量,其值为一个内存地址 引用是一个变量的新名字
    指针可以不初始化,而是在使用时赋值 引用必须在定义时初始化
    通过指针可以访问对应内存地址中的值 对引用的操作(赋值、取地址等)会传递到代表的变量上
    指针可以保存不同的地址 引用在初始化之后无法代表其他变量
    指针可以被const修饰,成为常量只读变量 const引用使其代表的变量具有只读属性

    在工程项目开发中

    • 当进行C++编程时,直接站在使用的角度,引用和指针没有任何关系
    • 当对C++代码进行调试分析时,一些特殊情况,可以考虑站在C++编译器的角度,引用在内部实现为指针常量

    我们给出一个站在C++编译器的角度看待引用的示例,下面这段代码有问题吗?

    int a = 1;
    int b = 2;
    int *pc = new int(3);
    int &array[] = {a, b, *pc};
    
    • 数组是一片连续的内存空间
    • 引用数组会破坏该特性,各元素代表的变量可能存储在不同的位置
    • 因此,C++不支持引用数组!!!!!!
    #include <stdio.h>
    
    int a = 1;
    
    struct SV
    {
        int &x;
        int &y;
        int &z;
    };
    
    int main()
    {
        int b = 2;
        int *c = new int(3);
        SV sv = {a, b, *c};
        int &array[] = {a, b, *c}; //&array[1] - &array[0] != 4,编译报错
    
        printf("&sv.x = %p
    ", &sv.x);
        printf("&sv.y = %p
    ", &sv.y);
        printf("&sv.z = %p
    ", &sv.z);
    
        delete c;
    
        return 0;
    }
    

    首先,注释掉代码第17行,编译运行结果如下,可以看出打印出的内存地址是各不相同的。

    然后,去除代码第17行注释,结果编译报错,原因就是数组的三个元素地址不连续,而是各不相同。

  • 相关阅读:
    python 面向对象编程的三大特征之一 多态
    python 访问控制
    python 面向对象编程的三大特征之一 继承
    朱兆祺教你如何攻破C语言学习、笔试与机试的难点
    如何画好流程图
    2013年个人计划
    30天敏捷结果(1):总体认识Getting Result敏捷方法
    每天一个linux命令目录
    国嵌C语言学习
    【head first python】1.初识python 人人都爱列表
  • 原文地址:https://www.cnblogs.com/songhe364826110/p/11518880.html
Copyright © 2020-2023  润新知