zoukankan      html  css  js  c++  java
  • 第5课 引用的本质分析

    1.  引用的意义

    (1)引用作为变量别名而存在,因此在一些场合可以代替指针

    (2)引用相对于指针来说,具有更好的可读性实用性

          

            

    2. 特殊的引用:const引用

    (1)在C++中可以声明const引用

    (2)const Type& name = var;   

    (3)const引用变量拥有只读属性

          

    (4)当使用常量对const引用进行初始化时C++编译器会为这个常量值分配空间,并将引用名作为这段空间的别名

    但这样用常量对const引用初始化生成的是一个只读变量

            

    【实例分析】引用的特殊意义  5-1.cpp

    #include <stdio.h>
    
                  
    
    void Example()
    
    {
    
        printf("Example:
    ");
    
     
    
        int a = 4;
    
        const int& b = a;//变量a的别名,const让变量b具有只读属性
    
        int* p = (int*)&b; //&b就是变量a的地址
    
     
    
        //b = 5;//非法,因为用const修饰的引用,其代表的变量是只读的
    
     
    
        *p = 5; //合法,修改变量a的值
    
     
    
        printf("a = %d
    ", a); //5;
    
        printf("b = %d
    ", b); //5
    
    }
    
     
    
    void Demo()
    
    {
    
        printf("Demo:
    ");
    
     
    
        //const引用
    
        const int& c = 1; //引用本应是变量的别名。一般,常量是不分配内存的。当编译器看
    
                          //该行时,会为常量1分配内存,并让b作为这段空间的别名。
    
     
    
        int* p = (int*)&c;
    
     
    
        //c = 5;//非法,因为const修饰,c是只读的
    
     
    
        *p = 5;//合法,通过指针访问内存
    
     
    
        printf("c = %d
    ", c); //5
    
     
    
        printf("
    ", c); //5
    
     
    
        //const修饰变量:注意与const引用的区别
    
        const int a = 1;  
    
        p = (int*)&a; //遇到&a才为常量分配内存
    
     
    
        //a = 5;//非法,因为const修饰,a是只读的
    
     
    
        *p = 5;//合法,通过指针访问内存
    
     
    
        printf("a = %d
    ", a); //1,编译器看到a直接从符号表读其值(1)
    
        printf("*p = %d
    ",*p); //5
    
    }
    
     
    
    int main()
    
    {
    
        Example();
    
       
    
        printf("
    ");
    
     
    
        Demo();
    
     
    
        return 0;    
    
    }

    运行结果:

      

    3. 引用的本质

    (1)引用C++中的内部实现是一个指针常量,因此引用占用的空间大小指针相同

             

    (2)从使用的角度引用只是一个别名C++为了实用性隐藏引用存储空间这一细节

      ①在编译过程中,编译器看到int& a的声明就会转换int* const a;

      ②看到使用引用时,转换*a,如此隐藏了使用指针的事实

    【编程实验】引用的思考  5-2.cpp

    #include <stdio.h>
    
     
    
    struct TRef
    
    {
    
        char& r; //引用的本质是指针常量,因此会分配4字节的空间,相当于char* const r;
    
    };
    
     
    
     
    
     
    
    int main()
    
    {
    
        char c = 'c';
    
        char& rc = c;
    
        TRef ref = {c};
    
     
    
        printf("sizeof(char&) = %d
    ",sizeof(char&));//1,char型变量别名,大小为1
    
        printf("sizeof(rc) = %d
    ",sizeof(rc));      //1,变量c的别名,大小为1
    
     
    
        printf("sizeof(TRef) = %d
    ",sizeof(TRef));  //结构体内有个引用,本质为指针,占4字节
    
        printf("sizeof(ref.r)= %d
    ",sizeof(ref.r)); //1,char型变量的别名,大小为1
    
     
    
     
    
        return 0;    
    
    }

    运行结果:

      

    【编程实验】引用的存储空间  5-3.cpp

    #include <stdio.h>
    
     
    
    struct TRef
    
    {
    
        char* before; //4字节
    
        char& ref;//4字节,本质是指针常量,会分配4字节的空间,相当于char* const ref;
    
        char* after;//4字节
    };
    
     
    int main()
    
    {
    
        char a = 'a';
    
        char& b = a;
    
        char c ='c';
    
     
    
        TRef r = {&a, b, &c};
    
     
    
        printf("sizeof(r) = %d
    ", sizeof(r));               //12
    
        printf("sizeof(r.before) = %d
    ", sizeof(r.before)); //4
    
        printf("sizeof(r.after)  = %d
    ", sizeof(r.after));  //4
    
        printf("&r.before = %p
    ", &r.before);
    
        printf("&r.after  = %p
    ", &r.after); //after和before相差8个字节,中间隔了个b引用所占用的空间
    
     
    
        return 0;    
    
    }

    运行结果:

      

    4. 引用的意义:C++中的引用旨在大多数的情况下代替指针

    (1)功能性引用在大多数情况下代替指针,可以满足多数需要使用指针的场合

    (2)安全性:可以避开由于指针操作不当带来的内存错误

    (3)操作性简单易用,又不失功能强大

    【实例分析】函数返回引用  5-4.cpp

    #include <stdio.h>
    
     
    
    int& demo()
    
    {
    
        int d = 0;
    
     
    
        printf("demo: d = %d
    ", d); //输出0
    
     
    
        return d;//返回局部变量的引用,危险
    
    }
    
     
    
    int& func()
    
    {
    
        static int s = 0;
    
        printf("func: s = %d
    ", s);//输出0
    
     
    
        return s; //合法,返回的是静态局部变量(位于全局存储区中的)
    
    }
     
    
    int main()
    
    {
    
        int& rd = demo();
    
        int& rs = func();
    
     
    
        printf("
    ");
    
        printf("main: rd = %d
    ", rd);//垃圾数值
    
        printf("main: rs = %d
    ", rs);//0,返回全局存储区中的s
    
        printf("
    ");
    
     
    
        return 0;    
    
    }

    运用结果:

      

    5. 小结

    (1)引用作为变量别名而存在,旨在代替指针

    (2)const引用可以使得变量具有只读属性

    (3)引用在编译器内部使用指针常量实现,其最终本质为指针

    (4)引用可以尽可能的避开内存错误

  • 相关阅读:
    WebDev.WebServer使用帮助
    [原创]通过编写PowerDesigner脚本功能批量修改属性
    Web中响应用户修改的事件
    郁闷的切换foxmail
    Java中Split函数的用法技巧
    [转].NET安装项目卸载的方法
    把你的名字刻到IE上
    JavaScript面向对象编程笔记
    附件下载直接显示另存为对话框并保存原有中文文件名的解决办法
    MyEclipse开发JSP页面假死问题解决办法
  • 原文地址:https://www.cnblogs.com/hoiday/p/10087892.html
Copyright © 2011-2022 走看看