zoukankan      html  css  js  c++  java
  • 引用的剖析

    《c++ primer》中这样写的:引用在内部存放的是一个对象的地址,它是该对象的别名。对于不可寻址的值,如文字常量,以及不同类型的对象,编译器为了实现引用,必须生成一个临时对象,引用实际上是指向该对象,但用户不能访问它。

    #include<iostream>
    
    #pragma pack(1)
    
    class data{
    public:    
        double data_a;
        double &data_ra;
        data():data_ra(data_a){  //引用不能在构造函数体内初始化,要在构造函数名称右边初始化
            data_a=1.0;
        }
    
    };
    
    int main(){
    
    
        double a=100;
        double &ra=a;
        double *pa=&a;
    
        printf("%d
    ",sizeof(ra));
        printf("%d
    ",sizeof(&ra));
        printf("%d
    ",sizeof(pa));
    
        data temp;
        temp.data_a=1.0;
        temp.data_ra=temp.data_a;
        printf("%d
    ",sizeof(temp));
        
        getchar();
        return 0;
    }

    为了防止字对齐的影响,以一个字节对齐后,发现类中的引用是4个字节,也就是一个指针的大小。(节约内存考虑)

    而main中引用是大小计算就是本来类型的大小,想想也是,引用本来就是一个对象的外号,指引用的时候就是指该对象。

    分析为什么会是这种结果呢?背后是什么机制在起作用?

    常量指针与指针常量我们都是知道的

    常量指针如 double const *P;  //即指针不能通过*P对变量赋值,p可以不初始化

        double a=100;
        double const*  cpa2=&a;
        a=2;//可以赋值
        //*cpa2=2;//编译会报错 不能这样赋值

    指针常量如 double * const p=&a;//指针所指的方向是不可改变的,且p必须初始化

    现在来看看,指针常量与引用何其相似,估计在底层引用就是通过指针常量实现的,再来看

    #include<iostream>
    using namespace std;
    
    
    int main(){
        double a=100;
        double &ra=a;
        double * const cpa=&a;
    
        printf("%d
    ",sizeof(a));
        printf("%d
    ",sizeof(ra));
        printf("%d
    ",sizeof(cpa));
        printf("%d
    ",sizeof(*cpa));//这里相当于printf("%d",sizeof(ra))
    
        getchar();
        return 0;
    }

    结果是 8 8 4 8

    指针常量 *cpa 类似引用ra的作用了,接着就可以解释为什么在类中引用是四个字节(cpa本来就是一个指针,指针的长度就是4),但在访问它的时候编译器就自动加上了*cpa,指向了对象,于是就是它原来类型的长度了。

    测试下,果然就是这么一回事。

    #include<iostream>
    
    #pragma pack(1)
    
    class data{
    public:    
        double data_a;
        double &data_ra;
        data():data_ra(data_a){  //引用不能在构造函数体内初始化,要在构造函数名称右边初始化
            data_a=1.0;
        }
    
    };
    
    int main(){
        data temp;
        temp.data_a=1.0;
        temp.data_ra=temp.data_a;
        printf("%d
    ",sizeof(temp));
        printf("%d
    ",sizeof(temp.data_a));
        printf("%d
    ",sizeof(temp.data_ra));
        
        getchar();
        return 0;
    }

    类的长度本来是12,而main中测试的时候成为了 8 + 8,符合了假说

    既然走到了这一步,为何不在看看汇编里对引用是怎么实现的。

    啊哈 ,引用通过间接寻址的方式获取了相应的数据,跟指针的间接寻址是类似的!

    引用设计的意义(既然设计出来一定是有他存在的道理的):引用的主要功能是传递函数的参数和返回值。C++语言中,函数的参数和返回值的传递方式有三种:值传递、指针传递和引用传递。 

    但是可以想象,引用能做的事,指针也同样可以做,并且指针的功能更为强大。那么为什么还需要引用呢?答案也许是指针虽然强大但是有时太肆无忌惮了,但是引用是个被约束过的‘指针’,需要一个变量的别名的时候就只要使用引用即可。eg:比如说,某人需要一份证明,本来在文件上盖上公章的印子就行了,如果把取公章的钥匙交给他,那么他就获得了不该有的权利。 

    总结:引用是一个被包装过的指针,实现机制类似指针常量

  • 相关阅读:
    一个 无私的 又不错的 博客
    byte[]与各种数据类型互相转换示例
    HttpClient之Get请求和Post请求示例
    jabberNet 发送出席信息
    jabberNet 修改花名册条目的昵称
    Openfire 配置连接SQL SERVER(非默认实例)
    WPF学习笔记——没有前途的WPF
    WPF学习笔记——设置ListBox选中项的背景颜色
    WPF学习笔记——为BUTTON添加背景图片
    EF + WCF学习笔记——EF实体类序列化
  • 原文地址:https://www.cnblogs.com/huhuuu/p/3481237.html
Copyright © 2011-2022 走看看