zoukankan      html  css  js  c++  java
  • C++学习笔记之 引用

    先声明一下,这里的内容大多是《C++编程思想》中的内容,我最近在学习C++,觉得里面的很多话不错,另外例子也都自己实验了一番,有些现象很有趣,希望与大家分享。

    •引用(reference)(&)就像能自动地被编译器间接引用的常量型指针。(常量型指针的含义就是常量修饰指针,即指的地方不变,但所指地方的内容可以改变。)

    #include <iostream>  
    using namespace std;  
    
    int y;
    int& r = y;//当一个引用被创建的时候,它必须被初始化为一个对象。
               //你也可以这样写:
    const int& q = 12;//(1)这时,引用就被绑定到一个存储位置中。
    int x=0;  //(2)   
    int& a =x;//(3)
    
    int main()  
    {  
        cout<<"x = "<<x<<",a = "<<a<<endl;
        a++;
        cout<<"x = "<<x<<",a = "<<a<<endl;
    
        system("pause");
        return 0;  
    }  

    代码运行结果:
    这里写图片描述

    在位置(1),编译器分配了一个存储单元,它的初始值被初始化为12,于是这个引用就和这个存储单元联系上了。应用要点是任何引用必须和存储单元联系。访问引用时,就是访问这个存储单元。因此,增加a事实上就是增加x,这个可在main()函数中显示出来,思考一个引用最简单的方法就是把它当做一个奇特的指针,这个指针的一个优点是不必怀疑它是否被初始化了(编译器强迫它初始化),也不必知道怎样对它间接引用(这由编译器做)。
    使用引用时有一定的规则:

    1.当引用被创建时,它必须被初始化(指针则可以在任何时候被初始化)。
    2.一旦一个引用被初始化为指向一个对象,它就不能改变为另一个对象的引用(指针则可以在任何时候指向另一个对象)。
    3.不可能有NULL引用。必须确保引用是和一块合法的存储单元关联。

    •函数中的引用:
    最经常看见引用的地方是在函数的参数和返回值中。当引用被用作函数参数时,在函数内任何对引用的更改将对函数外的参数产生改变。当然,可以通过传递一个指针来做相同的事情,但引用具有更清晰的语法。
    如果从函数中返回一个引用,必须像从函数中返回一个指针一样对待,当函数返回时,无论引用关联的是什么都应该存在,否则,将不知道指向哪一个内存。

    int& h()
    {
        int q;
        return q;//警告,返回的是局部变量或临时变量的地址
    }

    出现结果:这里写图片描述

    int& h()
    {
        static int x;
        return x;//OK
    }

    这样就没有报错。

    #include <iostream>  
    using namespace std;  
    
    int* f(int* x)
    {
        (*x)++;
        return x;
    }
    
    int& g(int& x)
    {
        x++;
        return x;
    }
    
    int main()  
    {  
        int a=0;
    
        cout<<"f(&a) = "<<f(&a)<<endl;
        cout<<"a = "<<a<<endl;
    
        cout<<"g(a) = "<<g(a)<<endl;
        cout<<"a = "<<a<<endl;
    
        system("pause");
        return 0;  
    }  

    这里写图片描述

    可见f()函数传进去的是a的地址,返回的也是a的地址。
    g()函数传进去的是a的引用,相当于传进去的a的存储单元的值,返回的是a的存储单元的值。
    对函数f()的调用缺乏使用引用的方便性和清晰性,但很清楚这是传递一个地址。在函数g()的调用中,地址通过引用被传递,但表面上看不出来。

    •常量引用
    刚刚函数中参数是非常量对象时,这个引用参数才能工作。如果是常量对象,函数g()将不接受这个参数,这样做是一件好事,因为这个函数将改变外部参数。如果知道这函数不妨碍对象的不变性的话,让这个参数是一个常量引用将允许这个函数在任何情况下使用。这意味着,对于用户定义的类型,该函数只能调用常量成员函数,而且不应当改变任何公共的数据成员。

    这样就已经报错了,因为你改变的是常量指针

    #include <iostream>  
    using namespace std;  
    
    void f(int& x)
    {
        x++;
    }
    
    void g(const int& x)
    {
        x++;
    }
    
    int main()  
    {  
        int a=0;
    
        f(1);
        g(1);
    
        system("pause");
        return 0;  
    }  
    

    这里写图片描述

    调用f(1)会产生编译期间错误,这是因为编译器必须首先建立一个引用,即编译器为一个int类型分派存储单元,同时将其初始化为1并为其产生一个地址和引用捆绑在一起。存储的内容必须是常量,因为改变它没有任何意义,我们再不能对它进行操作。当改变这种数据的时候,编译器会指出错误,这是非常有用的提示,因为这个改变会导致信息丢失。

    •指针引用

    在C语言中,如果想改变指针本身而不是它所指向的内容,函数声明可能像这样:

    void f(int **)

    当传递它时,必须取得指针的地址:

    int i = 47;
    int* ip = &i;
    f(&ip);

    对于C++中的引用,语法清晰多了。函数参数变成指针的引用,用不着取得指针的地址。
    int*& i理解的话,相比于int& i。我的理解是int*& i, i首先是一个引用,之后是对int*的引用,即指针的引用。

    #include <iostream>  
    using namespace std;  
    
    void increment(int*& i)
    {
        i++;
    }
    
    
    int main()  
    {  
        int* i=0;
    
        cout<<"i = "<<i<<endl;
        increment(i);
        cout<<"i = "<<i<<endl;
    
        system("pause");
        return 0;  
    }  

    结果很有意思,定义i是一个指针,指向的地址是0。执行increment(i)函数之后,指针加一,因为是整型变量的指针,指向下一个整型变量,内存地址就加了4。所以结果是:

    这里写图片描述

    有什么说错的地方,还望大家多多指正。

    版权声明:本文为博主原创文章,未经博主允许不得转载。

  • 相关阅读:
    swiper插件的使用demo
    可能要用的东西
    VIDEO
    vue上传图片加水印
    图片 base64 file blob 之间相互的转化
    vant 上传图片加水印
    JS 随机排序算法
    ubuntu16.04 下apache 搭建站点
    Unity常用目录对应的Android && iOS平台地址
    IOS 官方实现单例模式
  • 原文地址:https://www.cnblogs.com/lightspeedsmallson/p/4785889.html
Copyright © 2011-2022 走看看