C++ 引用

2023-12-13 04:32:36

在C++ 中,我们可以使用变量(variable)来存储数据,变量有两个重要的属性:类型(type)和(value)。类型决定了变量可以存储什么样的数据,以及可以进行什么样的操作,例如int 类型的变量可以存储整数,可以进行加减乘除等算术运算。值决定了变量存储的具体的数据,例如int a = 10; 就是定义了一个int 类型的变量a,并赋值为10

除了类型和值之外,变量还有另一个重要的属性:地址(address)。地址是变量在内存中的位置,可以用一个十六进制的数来表示,例如0x7fffbf4c。我们可以使用取地址运算符(&)来获取变量的地址,例如&a 就是获取变量a 的地址。地址是变量的唯一标识,不同的变量有不同的地址,同一个变量在不同的时间也可能有不同的地址,因为变量可能被分配到不同的内存空间。

有了地址,我们就可以使用指针(pointer)来操作变量。指针是一种特殊的变量,它的类型是指针类型(pointer type),它的值是地址值(address value),它的作用是指向(point to)另一个变量。我们可以使用指针运算符(*)来获取指针指向的变量的值,例如*p 就是获取指针p 指向的变量的值。指针的优点是可以间接地访问和修改变量的值,而不需要知道变量的名字,这样可以提高代码的灵活性和效率。指针的缺点是容易出错,因为指针可能指向一个不存在或者无效的地址,导致程序崩溃或者数据损坏。

为了解决指针的缺点,C++ 引入了一种新的概念:引用(reference)。引用是一种特殊的变量,它的类型是引用类型(reference type),它的值是别名(alias),它的作用是引用(refer to)另一个变量。引用的本质是一个常量指针,它在定义时必须初始化为一个已存在的变量的地址,然后就可以使用引用的名字来访问和修改被引用的变量的值,而不需要使用指针运算符。引用的优点是可以直接地访问和修改变量的值,而不需要知道变量的地址,这样可以提高代码的可读性和安全性。引用的缺点是不能改变引用的目标,一旦引用被初始化为一个变量,就不能再引用另一个变量。

引用的定义和使用

引用的定义和使用有以下的规则和注意事项:

  • 引用的定义格式为:Type & name = var;,其中Type 是被引用的变量的类型,name 是引用的名字,var 是被引用的变量的名字。例如,int &a = b; 就是定义了一个int 类型的引用a,并初始化为变量b
  • 引用的定义时必须进行初始化,不能定义一个空引用,也不能定义一个指向无效地址的引用。例如,int &a; 或者int &a = 10; 都是错误的,因为没有指定引用的目标。
  • 引用的初始化后不能改变引用的目标,即不能让引用指向另一个变量。例如,int &a = b; a = c; 并不是让引用a 指向变量c,而是让变量b 的值变成和变量c 一样。
  • 引用的类型必须和被引用的变量的类型一致,或者可以进行隐式类型转换。例如,int &a = b; 中,ab 的类型都必须是int,或者b 的类型可以隐式转换为int,例如charshort 等。
  • 引用的名字可以和被引用的变量的名字相同,但是不建议这样做,因为会造成混淆。例如,int a = 10; int &a = a; 是合法的,但是不推荐。

下面是一个引用的定义和使用的例子:

#include <iostream>
using namespace std;

int main() {
    // 定义一个普通的变量
    int a = 10;
    // 定义一个引用,初始化为变量a
    int &b = a;
    // 输出变量a和引用b的值和地址
    cout << "a = " << a << ", &a = " << &a << endl;
    cout << "b = " << b << ", &b = " << &b << endl;
    // 修改引用b的值,相当于修改变量a的值
    b = 20;
    // 输出变量a和引用b的值和地址
    cout << "a = " << a << ", &a = " << &a << endl;
    cout << "b = " << b << ", &b = " << &b << endl;
    return 0;
}

输出结果为:

a = 10, &a = 0x7ffeeb9f8a64
b = 10, &b = 0x7ffeeb9f8a64
a = 20, &a = 0x7ffeeb9f8a64
b = 20, &b = 0x7ffeeb9f8a64

从输出结果可以看出,变量a 和引用b 的值和地址都是相同的,说明引用b 就是变量a 的别名,通过引用b 可以直接访问和修改变量a 的值。

引用作为函数参数

引用的一个重要的用途是作为函数的参数,这样可以实现以下的目的:

  • 减少函数调用的开销,避免复制大量的数据,提高程序的效率。
  • 实现函数的多个返回值,通过引用参数可以修改实参的值,从而返回更多的信息。
  • 实现函数的重载,通过不同类型的引用参数可以区分不同的函数,从而实现多态。

引用作为函数参数有以下的规则和注意事项:

  • 引用参数的定义格式为:Type & name,其中Type?是被引用的变量的类型,name?是引用的名字。例如,void swap(int &a, int &b)?就是定义了一个交换两个整数的函数,它的参数是两个整数的引用。
  • 引用参数的调用格式为:var,其中var?是被引用的变量的名字。例如,swap(x, y)?就是调用交换两个整数的函数,它的实参是两个整数的变量x?和y
  • 引用参数的作用是将实参的地址传递给形参,从而使形参和实参指向同一个变量,通过形参可以直接访问和修改实参的值,而不需要返回值。例如,swap(x, y)?就是将变量x?和y?的地址传递给引用a?和b,从而使a?和xb?和y?指向同一个变量,通过a?和b?可以直接交换x?和y?的值,而不需要返回值。
  • 引用参数的优点是可以减少函数调用的开销,避免复制大量的数据,提高程序的效率。例如,如果我们要交换两个数组的值,如果使用普通的参数,就需要复制两个数组的所有元素,这样会占用大量的内存和时间,如果使用引用参数,就只需要传递两个数组的地址,这样会节省大量的内存和时间。
  • 引用参数的优点是可以实现函数的多个返回值,通过引用参数可以修改实参的值,从而返回更多的信息。例如,如果我们要计算两个整数的最大公约数和最小公倍数,如果使用普通的参数,就只能返回一个值,如果使用引用参数,就可以返回两个值,一个是最大公约数,一个是最小公倍数。
  • 引用参数的优点是可以实现函数的重载,通过不同类型的引用参数可以区分不同的函数,从而实现多态。例如,如果我们要定义一个打印函数,可以根据不同类型的引用参数来重载打印函数,从而实现对不同类型的数据的打印。

下面是一个引用作为函数参数的例子:

#include <iostream>
using namespace std;

// 定义一个交换两个整数的函数,参数是两个整数的引用
void swap(int &a, int &b) {
    // 定义一个临时变量,用于存储一个整数的值
    int temp = a;
    // 将第二个整数的值赋给第一个整数
    a = b;
    // 将临时变量的值赋给第二个整数
    b = temp;
}

// 定义一个计算两个整数的最大公约数和最小公倍数的函数,参数是两个整数的值和两个整数的引用
void gcd_lcm(int a, int b, int &gcd, int &lcm) {
    // 定义一个临时变量,用于存储两个整数的乘积
    int product = a * b;
    // 使用辗转相除法求最大公约数
    while (b != 0) {
        int r = a % b;
        a = b;
        b = r;
    }
    // 将最大公约数赋给引用参数
    gcd = a;
    // 使用公式求最小公倍数
    lcm = product / gcd;
}

// 定义一个打印整数的函数,参数是一个整数的引用
void print(int &a) {
    // 输出整数的值
    cout << "The integer is: " << a << endl;
}

// 定义一个打印字符串的函数,参数是一个字符串的引用
void print(string &s) {
    // 输出字符串的内容
    cout << "The string is: " << s << endl;
}

// 主函数,用于测试
int main() {
    // 定义两个整数变量
    int x = 10;
    int y = 20;
    // 调用交换函数,实现两个整数的交换
    swap(x, y);
    // 输出交换后的结果
    cout << "x = " << x << ", y = " << y << endl; // 输出结果为:x = 20, y = 10
    // 定义两个整数变量
    int a = 12;
    int b = 18;
    // 定义两个整数变量,用于存储最大公约数和最小公倍数
    int gcd, lcm;
    // 调用计算函数,实现两个整数的最大公约数和最小公倍数的计算
    gcd_lcm(a, b, gcd, lcm);
    // 输出计算后的结果
    cout << "The gcd of " << a << " and " << b << " is: " << gcd << endl; // 输出结果为:The gcd of 12 and 18 is: 6
    cout << "The lcm of " << a << " and " << b << " is: " << lcm << endl; // 输出结果为:The lcm of 12 and 18 is: 36
    // 定义一个整数变量
    int c = 100;
    // 调用打印函数,实现整数的打印
    print(c); // 输出结果为:The integer is: 100
    // 定义一个字符串变量
    string s = "Hello";
    // 调用打印函数,实现字符串的打印
    print(s); // 输出结果为:The string is: Hello
    return 0;
}

从上面的代码可以看出,引用作为函数参数可以实现以下的目的:

  • 减少函数调用的开销,避免复制大量的数据,提高程序的效率。例如,swap(x, y)?就是通过引用参数来交换两个整数的值,而不需要复制两个整数的值。
  • 实现函数的多个返回值,通过引用参数可以修改实参的值,从而返回更多的信息。例如,gcd_lcm(a, b, gcd, lcm)?就是通过引用参数来返回两个整数的最大公约数和最小公倍数,而不需要返回一个值。
  • 实现函数的重载,通过不同类型的引用参数可以区分不同的函数,从而实现多态。例如,print(c)?和print(s)?就是根据不同类型的引用参数来调用不同的打印函数,从而实现对不同类型的数据的打印。

文章来源:https://blog.csdn.net/fasdfasfwerwqf/article/details/134824970
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。