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:比如说,某人需要一份证明,本来在文件上盖上公章的印子就行了,如果把取公章的钥匙交给他,那么他就获得了不该有的权利。 

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

  • 相关阅读:
    changing a pointer rather than erasing memory cells
    验证码识别 edge enhancement 轮廓增强 region finding 区域查找
    Manipulating Data Structures
    passing parameters by value is inefficient when the parameters represent large blocks of data
    Aliasing 走样
    Artificial Intelligence Research Methodologies 人工智能研究方法
    Thread safety
    include pointers as a primitive data type
    flat file
    functional cohesion
  • 原文地址:https://www.cnblogs.com/huhuuu/p/3481237.html
Copyright © 2011-2022 走看看