技术交流QQ群:1027579432,欢迎你的加入!

1.Cpp中的引用

  • 引用变量是一个别名,即它是某个已经存在变量的另一个名字。一旦把引用初始化为某个变量,就可以使用该引用名称或变量名称来指向变量。

2.Cpp中的引用VS指针

  • 引用与指针之间的区别:
    • 不存在空的引用,引用必须要连接到一块的合法内存
    • 一旦引用被初始化为一个对象,就不能被指向另一个对象,指针可以在任何时候指向到另一个对象
    • 引用必须在创建时被初始化,指针可以在任何时间被初始化。

3.Cpp中创建引用

  • 可以把变量名称想象成为变量附属在内存位置的标签,可以把引用当成是变量附属在内存位置的第二个标签。因此,可以通过原始变量名称或引用来访问变量的内容。如下面的例子:
    int i = 7;
        int &r = i;  // r是一个初始化为i的int型引用
        double &s = d;  // s是一个初始化为d的double类型引用
  • 具体的程序实例如下:
    // 声明简单变量
            int i;
            double d;
            // 声明引用变量
            int &r = i; // 与int r = i;的区别是内存的分配,后者会再分配一个内存空间
            double &s = d;
    
            i = 5;
            cout << "i = " << i << endl;
            cout << "i的引用是: " << r << endl;
            cout << "i的地址是: " << &i << endl;
            cout << "r的地址是: " << &r << endl;
    
            d = 11.7;
            cout << "d = " << d << endl;
            cout << "d的引用是: " << s << endl;
    
            /*注意与上面的对比不同*/
            int x;
            int y = x;
            x = 6;
            cout << "x = " << x << endl;
            cout << "y = " << y << endl;
            cout << "x的地址是: " << &x << endl;
            cout << "y的地址是: " << &y << endl;

4.Cpp中的引用作为参数

  • 引用通常用于函数参数列表和函数返回值,两者的区别是:


    引用的作用.png
  • 4.1 引用作为函数参数
  • 引用作为函数参数,C++之所以增加引用类型,主要是把它作为函数参数,以扩充函数传递数据的功能。C++中函数传递参数的几种方法:
    • 将变量名作为实参和形参。这时传给形参的是变量的值,传递时单向的。如果在执行函数期间形参的值发生变化,并不传回给实参。因为在调用函数时,形参和实参不是同一个存储单元。
    • 传递变量的地址。形参是指针变量,实参是一个变量的地址。调用函数时,形参(指针变量)指向的是实参变量的内存单元,这种通过形参指针可以改变实参的值。
    • C++提供了传递变量的引用。形参是引用变量,和实参是一个变量。调用函数时,形参(引用变量)指向实参变量的内存单元,这种通过形参引用可以改变实参的值。
    void swap(int &x, int &y){
            int temp;
            temp = x;
            x = y;
            y = temp;
        }
    
        // 引用作为函数参数
            int a = 100;
            int b = 200;
            cout << "没有交换前a,b的值分别是: a = " << a << ",b = " << b << endl; 
            swap(a, b);
            cout << "交换后a,b的值分别是: a = " << a << ",b = " << b << endl;
  • 4.2 引用作为函数的返回值
  • 通过使用引用来代替指针,会使C++程序更容易阅读和维护。C++函数可以返回一个引用,方法与返回一个指针类似。当函数返回一个指针时,则返回一个指向返回值的隐式指针。这样,函数就可以放在赋值语句的左边,见下面的例子:
    // 引用作为函数的返回值
        double &setValues(int i, double *arr){
            return arr[i];
        }
        
        double vals[] = {10.1, 12.6, 3.14, 24.1, 50.5};
        cout << "数组没改变前的值: " << endl;
        for (int i = 0; i < 5; i++)
            cout << "vals[" << i << "] = " << vals[i] << endl;
        cout << "数组改变后的值: " << endl;
        setValues(1, vals) = 20.23;  // 改变数组的第2个元素
        setValues(3, vals) = 78.99;  // 改变数组的第4个元素
        for (int i = 0; i < 5; i++)
            cout << "vals[" << i << "] = " << vals[i] << endl;
  • 注意:当返回一个引用时,要注意被引用的对象不能超过作用域。所以,返回一个对局部变量的引用是不合法的,但是,可以返回一个静态变量的引用!
int & func(){
    int q;
    return q;  // 在编译时报错
    static int x;
    return x; // 安全,x在函数作用域外仍然是有效的
}
  • 引用作为函数返回值,其他注意地方:
    • 以引用返回函数值,定义函数时需要在函数名前加&
    • 用引用返回一个函数值的最大好处是:在内存中不产生被返回值的副本
    • 引用作为返回值时,必须遵守下面的规则:
      • 不能返回局部变量的引用。主要原因是局部变量会在函数返回后被销毁,因此被返回的引用就成了"无所指"的引用,程序会进入未知状态。
      • 不能返回函数内部new分配的内存的引用。虽然不存在局部变量的被动销毁问题,可对于这种情况下(返回函数内部new分配内存的引用),又会面临其他尴尬局面。例如,被函数返回的引用只是作为一个临时变量出现,而没有被赋予一个实际的变量,那么这个引用所指向的空间(由new分配)就无法释放,造成内存泄漏。
      • 可以返回类成员的引用,但是最好是const。主要原因是当对象的属性是与某种业务规则相关联的时候,其赋值常常与某些其他属性或者对象的状态有关,因此有必要将赋值操作封装在一个业务规则当中。如果其他对象可以获得该属性的非常量引用(指针),那么对该属性的单纯赋值就会破坏业务规则的完整性。

5.C++中的引用类型总结

  • 引用:就是变量的一个别名,作为别名来说,一个变量不能只有别名,而没有自己的真实姓名。


    引用的形象化表示.png
  • 5.1 基本数据类型的引用
    int a = 3;
        int &b = a;  // b就是a的引用,即b是a的一个别名;引用必须初始化,否则会编译错误
        b = 10;
        cout << "a = " << a << endl; // 此时a的值已经由原来的3变成了10,因此对别名b做任何操作,其实质都是对变量a本身做操作!
  • 5.2 结构体类型的引用
    typedef struct{
            int age;
            char name;
            double salary;
        }Student;
    
        void print_info(){
            Student s1; // 定义一个结构体变量,s1
            Student &s = s1; // 给s1起了一个别名叫s
            s.age = 20;  // 通过引用给结构体变量的数据成员赋值
            s.name = 'A';
            cout << "s.age = " << s.age << ", s.name = " << s.name << endl;
        }
    
        print_info()  // 调用上面的函数
  • 5.3 指针类型的引用
  • 指针类型的引用是当中最复杂的,最难理解的,同时在写法上也不一样。定义:
    类型 *&指针引用名 = 指针;
  • 参见下面的实例:
    // 指针类型的引用
        int m = 10; // 定义一个整型的变量a
        int *p = &m; // 定义一个指向变量a的指针p
        int *&p_reference = p;  // 定义指针p的引用p_reference即是p的别名
        *p_reference = 20; // 把20赋值给*p_reference,相当于把20赋值给*p,也就是相当于把值赋值给a
        cout << "m = " << m << endl;