JHHK

欢迎来到我的个人网站
行者常至 为者常成

5、引用的本质(二)

目录

通过汇编分析指针

void pointerNature(void){
    int age = 3;
    int *p = &age;
    *p = 5;
    /**
         0x100009c40 <+0>:  pushq  %rbp
         0x100009c41 <+1>:  movq   %rsp, %rbp
     
        //将立即数 0x3 放入地址 -0x4(%rbp)
     ->  0x100009c44 <+4>:  movl   $0x3, -0x4(%rbp)     //-0x4(%rbp)变量age的地址;int age = 3;
     
        //将地址 -0x4(%rbp) 放入寄存器 %rax
         0x100009c4b <+11>: leaq   -0x4(%rbp), %rax     //&age 放入寄存器rax;      rax = &age;
     
        //将寄存器内的内容放入地址 -0x10(%rbp)
         0x100009c4f <+15>: movq   %rax, -0x10(%rbp)    //-0x10(%rbp)变量p的地址;  int * p = rax;
     
        //将地址-0x10(%rbp)内的内容放到寄存器%rax
         0x100009c53 <+19>: movq   -0x10(%rbp), %rax    //                       rax = *p = &age;
     
        //将立即数$0x5放入 寄存器(%rax)内存放的地址
         0x100009c57 <+23>: movl   $0x5, (%rax)         //                       rax=*p=&age=5;
     
     
         0x100009c5d <+29>: popq   %rbp
         0x100009c5e <+30>: retq
     */
}

通过汇编分析引用

void referenceNatureByAssembly(void){
    
    int age = 3;
    int &p = age;
    p = 5;
    
    /**
         0x100009c40 <+0>:  pushq  %rbp
         0x100009c41 <+1>:  movq   %rsp, %rbp
     
     ->  0x100009c44 <+4>:  movl   $0x3, -0x4(%rbp)
         0x100009c4b <+11>: leaq   -0x4(%rbp), %rax
         0x100009c4f <+15>: movq   %rax, -0x10(%rbp)
         0x100009c53 <+19>: movq   -0x10(%rbp), %rax
         0x100009c57 <+23>: movl   $0x5, (%rax)
     
         0x100009c5d <+29>: popq   %rbp
         0x100009c5e <+30>: retq

     */
    
    //汇编代码与指针的汇编代码 一模一样,引用的本质就是指针
}

其它数据类型的引用

struct Date{
    int year;
    int month;
    int day;
};

void referenceWithOtherType(void){
    
    //1、结构体的引用
    Date d = {2011,2,1};
    Date &ref = d;
    ref.year = 2012;
    cout<<"d.year = "<<d.year<<endl;
    
    
    
    //2、指针的引用
    int age = 10;
    int * p = &age;
    int * & ref2 = p;
    int height = 180;
    ref2 = &height;
    cout<<"*ref2 = "<<*ref2<<endl;
    cout<<"*p = "<<*p<<endl;
    
    
    
    //3、数组
    {
        int array[3] = {1,2,3};
        int * a = array;
    }
   
    {
        //指针数组,数组里面可以存放3个int *
        int age1 = 10,  age2 = 20 , age3 = 30;
        int *ap1 = &age1 , *ap2 = &age2 , *ap3 = &age3;
        int * array[3] = {ap1,ap2,ap3};
        int ** a = array;
    }
    
    {
        //指向数组的指针
        int array[3] = {1,2,3};
        int (*p)[3] = &array;
    }
    
    
    
    //4、数组的引用
    {
        int array[3] = {1,2,3};
        //方式一:
        int (&ref)[3] = array;
        //方式二:
        int * const & ref2 = array;//array是数组的首地址是一个常量
        
        ref[1] = 4;
        cout<<"array[1] = "<<array[1]<<endl;
        cout<<"ref[1] = "<<ref[1]<<endl;
        cout<<"ref2[1] = "<<ref2[1]<<endl;
    }
    
    {
        int age = 10;
        int ageRef = age;
        //不存在引用数组
        //int& array[3] = {ageRef,ageRef,ageRef};
    }
   
    
    //5、不存在引用的引用
    {
        int age = 10;
        int &refAge = age;
        //int &&rrAge = ref;//错误不存在引用的引用
    }
}

常引用

int constRefTest(const int &a){
    //函数内部不可对a进行修改,保护变量a
    //a = 20;
    return a+10;//可以访问
}


int pointerTest(const int* a){
    //函数内部不可更改变量a存储的内容,保护变量a
    //*a = 20;
    return *a+10;//可以访问
}


void constReference(void){
    
    //1
    int age = 10;
    const int &ref = age;
    //ref = 20;//常引用,不可对ref赋值
    
    /**
     因为引用的本质是指针
     const int & ref = age;
     const int * ref1 = &age;
     
     ref 相当于 *ref1,*ref1 不可修改,所以 ref不可修改
     
     int const & ref 与 const int & ref 相同
     */
    
    
    
    //2
    //int & const reff = age;//报错可能是有的编译器不支持
    //reff = 20;//可以修改
    
    /**
     因为引用的本质是指针
     int & const reff = age;
     int * const reff1 = *age;
     reff可以修改,就类似与 *reff1可以修改一样
     */
}

常引用可以指向临时变量

指向临时变量

int sumTest(int a,int b){
    return a+b;
}

void constReferenceTemp(void){
    
    //1、常引用可以指向临时变量
    {
        //int &ref = 30;//报错
        const int &reff = 30;
        //reff = 20;//因为是常量不可修改
        cout<<"reff = "<<reff<<endl;
    }
    
    
    //2、常引用指向函数返回值
    {
        //返回值int 是一个常量
        //int & ref = sumTest(1, 2);
        
        const int & reff = sumTest(1, 2);
        //reff = 4;//因为是常量不可修改
        cout<<"reff = "<<reff<<endl;
    }
    
    
    
    //3、
    {
        int age = 10;
        const int &ref = age;
        //ref = 30;//不可更改
        age = 30;//可以修改
        cout<<"age = "<<age<<endl;//30
        cout<<"ref = "<<ref<<endl;//30
    }
    
    
    //4、
    {
        int age = 10;
        
        //引用指向了不同的类型,需要用const
        //long & ref = age;
        
        //当常引用指向了不同类型的数据时,会产生临时变量,所以修改age不会更改reff的值
        const long & reff = age;
        cout<<"reff = "<<reff<<endl;//30
        
        age = 40;
        cout<<"age = "<<age<<endl;//40
        cout<<"reff = "<<reff<<endl;//30
    }
}

作为参数

/**
 可以接受常量,const修饰的变量,非const修饰的变量
 const修饰传递的参数范围比较大
 */
int sumTest2(const int&a,const int&b){
    cout<<"int sumTest2(const int&a,const int&b)"<<endl;
    return a + b;
}


/**
 const 修饰引用或指针(本质相同)作为参数时,可构成重载
 const 修饰非引用或非指针时不构成重载
 */
int sumTest2(int &a,int &b){
    cout<<"int sumTest2(int &a,int &b)"<<endl;
    return a+b;
}



void constReferenceTemp2(void){
    
    //非const修饰的变量
    int a = 10;
    int b = 20;
    sumTest2(a, b);
   
    
    //const 修饰的变量
    const int a1 = 10;
    const int b1 = 20;
    sumTest2(a1, b1);
    
    
    //非const修饰的变量
    int & refa1 = a;
    int & refb1 = b;
    sumTest2(refa1, refb1);
    
    
    //const 修饰的变量
    const int &refa2 = a;
    const int &refb2 = b;
    sumTest2(refa2, refb2);//如果函数参数去掉const 此处调用会报错
}

行者常至,为者常成!





R
Valine - A simple comment system based on Leancloud.