35.引用和函数

35.引用-引用和函数


35.1 知识点

使用引用传递函数参数

左值引用参数函数

此函数接收左值引用作为参数,允许在函数内部修改原始对象。避免了参数传递时的拷贝操作,提高性能,同时函数内的操作直接影响传入的对象。

遵守引用使用的一般规则:

  • 引用变量的类型必须和引用的内容类型一致。
  • 引用绑定的对象不能更改(指引用的绑定关系,而不是引用所指向对象的值)。
  • 引用不会占用新的内存空间,它只是原变量的另一种名称。
  • 传递引用时,对象的生命周期取决于外部,不会因函数调用结束而释放。
void changeValue(int& value)
{
    // 修改引用所指向的对象的值
    value = 10;
}
// 调用左值引用参数函数,传入的实参在函数里修改了值,外面的实参也会相应改变
int a = 99;
changeValue(a);
cout << "修改后 a 的值: " << a << endl; // 10

右值引用参数函数

右值引用主要用于优化性能,特别是对于临时对象或大对象,避免不必要的拷贝。可以直接操作传入的右值,提升程序效率。虽然目前可能难以完全理解其优势,但在更复杂的场景中会更明显。

void changeValue(int&& value)
{
    // 输出右值的值
    cout << "传入的右值: " << value << endl;
}
// 对于右值引用参数,可以利用它避免不必要的临时对象创建,从而优化性能和节约内存
// 直接将右值作为参数传入函数
changeValue(10); // 10

常量引用参数

常量引用参数函数接收常量引用作为参数,保证函数内不会修改引用所指向的对象。适用于只读操作,避免拷贝开销,特别是对于大型对象或不可修改的对象。通常在左值引用参数上使用 const,而右值引用加 const 的意义不大。

void getValue(const int& value)
{
    // 尝试修改常量引用会导致编译错误
    // value = 10; 
    // 输出常量引用的值
    cout << "常量引用的值: " << value << endl;
}
// 使用常量引用参数的函数调用,适用于只读操作,避免不必要的拷贝
getValue(666); // 666

函数返回引用

函数返回引用时需要注意:不能返回局部变量的引用,因为局部变量在函数结束时会被销毁,返回其引用会导致未定义行为。此函数返回传入参数的引用,使用时需注意引用的生命周期。

int& getRef(int& d)
{
    // 错误示例,以下代码会导致未定义行为,因为 b 是局部变量,函数结束后被销毁
    // int b = 10;
    // return b;

    // 正确示例,返回传入参数的引用
    return d;
}
int c = 99;
int& d = getRef(c);
// 修改 d 的值,由于 d 是 c 的引用,c 的值也会相应改变
d = 888;
cout << "修改后 c 的值: " << c << endl; // 888

35.2 知识点代码

Lesson35_引用_引用和函数.cpp

#include <iostream>
using namespace std;

// 函数声明
void changeValue(int& value);
void changeValue(int&& value);
void getValue(const int& value);
int& getRef(int& d);

int main()
{
    std::cout << "引用和函数\n";

    #pragma region 知识点一 使用引用传递函数参数

    // 调用左值引用参数函数,传入的实参在函数里修改了值,外面的实参也会相应改变
    int a = 99;
    changeValue(a);
    cout << "修改后 a 的值: " << a << endl;//10

    // 对于右值引用参数,可以利用它避免不必要的临时对象创建,从而优化性能和节约内存
    // 直接将右值作为参数传入函数
    changeValue(10);//10

    #pragma endregion

    #pragma region 知识点二 常量引用参数

    // 使用常量引用参数的函数调用,适用于只读操作,避免不必要的拷贝
    getValue(666);//666

    #pragma endregion

    #pragma region 知识点三 函数返回引用

    int c = 99;
    int& d = getRef(c);
    // 修改 d 的值,由于 d 是 c 的引用,c 的值也会相应改变
    d = 888;
    cout << "修改后 c 的值: " << c << endl;//888

    #pragma endregion
}

#pragma region 知识点一 使用引用传递函数参数

// 左值引用参数函数
// 此函数接收左值引用作为参数,允许在函数内部修改原始对象
// 避免了参数传递时的拷贝操作,提高性能,同时函数内的操作直接影响传入的对象
// 遵守引用使用的一般规则:
// 1. 引用变量的类型必须和引用的内容类型一致
// 2. 引用绑定的对象不能更改(指引用的绑定关系,而不是引用所指向对象的值)
// 3. 引用不会占用新的内存空间,它只是原变量的另一种名称
// 4. 传递引用时,对象的生命周期取决于外部,不会因函数调用结束而释放
void changeValue(int& value)
{
    // 修改引用所指向的对象的值
    value = 10;
}

// 右值引用参数函数
// 主要用于优化性能,特别是对于临时对象或大对象,避免不必要的拷贝
// 可以直接操作传入的右值,提升程序效率
// 目前可能难以完全理解其优势,后续在更复杂的场景中会更明显
void changeValue(int&& value)
{
    // 输出右值的值
    cout << "传入的右值: " << value << endl;
}

#pragma endregion

#pragma region 知识点二 常量引用参数

// 常量引用参数函数
// 接收常量引用作为参数,保证函数内不会修改引用所指向的对象
// 适用于只读操作,避免拷贝开销,特别是对于大型对象或不可修改的对象
// 通常在左值引用参数上使用 const,右值引用加 const 意义不大
void getValue(const int& value)
{
    // 尝试修改常量引用会导致编译错误
    // value = 10; 
    // 输出常量引用的值
    cout << "常量引用的值: " << value << endl;
}

#pragma endregion

#pragma region 知识点三 函数返回引用

// 函数返回引用
// 注意:不能返回局部变量的引用,因为局部变量在函数结束时会被销毁,返回其引用会导致未定义行为
// 此函数返回传入参数的引用,使用时需注意引用的生命周期
int& getRef(int& d)
{
    // 错误示例,以下代码会导致未定义行为,因为 b 是局部变量,函数结束后被销毁
    // int b = 10;
    // return b;

    // 正确示例,返回传入参数的引用
    return d;
}

#pragma endregion

35.3 练习题

请为一维数组、二维数组、指针声明一个引用别名

// 一维数组
int arr[5] = { 1, 2, 3, 4, 5 };
// 二维数组
int arr2D[3][4] = { {1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12} };
// 普通 int 指针
int x = 10;
int* ptr = &x;

// 普通的和单个变量绑定引用 用于在语法上和下面其他引用对比
int& refX = x;

// 为一维数组声明引用别名
int(&arr1)[5] = arr; // arr1一个别名了
typedef int(&arrRef)[5];
arrRef ref_arr = arr; // ref_arr是一个别名了

// 为二维数组声明引用别名
int(&arr2D1)[3][4] = arr2D; // arr2D1一个别名了
typedef int(&arr2DRef)[3][4];
arr2DRef ref_arr2D = arr2D; // ref_arr2D是一个别名了

// 为普通 int 指针声明引用别名
int*& ptrRef = ptr;

// 输出元素验证
cout << "一维数组引用元素: " << arr1[1] << endl; // 2
cout << "一维数组引用元素: " << ref_arr[2] << endl; // 3
cout << "二维数组引用元素: " << arr2D1[0][0] << endl; // 1
cout << "二维数组引用元素: " << ref_arr2D[1][1] << endl; // 6
cout << "指针引用元素: " << *ptrRef << endl; // 10

编写一个函数,接收一个 int 类型的左值引用作为参数,将其值加1。调用该函数后,验证原变量的值是否被修改

void addRef(int& value)
{
    value += 1;
}

int bb = 22;
addRef(bb);
cout << bb << endl; // 23

编写一个函数,返回一个数组中某个元素的左值引用,并通过该引用修改数组中元素的值

int& changeArrayValue(int array[], int index)
{
    return array[index];
}

int array[] = { 1, 2, 3, 4, 5 };

// int& value = changeArrayValue(array, 2);
// value = 99;
changeArrayValue(array, 2) = 99;

for (int i = 0; i < 5; i++)
{
    cout << array[i] << endl;
}
// 1 2 99 4 5

编写一个函数,使用 const 左值引用接收参数并打印参数值,确保函数能接受左值和右值

// 对于常量左值引用参数来说,不仅可以传入左值,也可以传入右值
void test(const int& value)
{
    cout << value << endl;
}

// 对于常量左值引用参数来说,不仅可以传入左值,也可以传入右值
int cc = 666;
test(cc); // 666
test(999); // 999

35.4 练习题代码

Lesson35_练习题.cpp

#include <iostream>
using namespace std;

void addRef(int& value);
int& changeArrayValue(int array[], int index);
void test(const int& value);

int main()
{
    std::cout << "引用和函数练习题\n";


    #pragma region 练习题一 

    // 一维数组
    int arr[5] = { 1, 2, 3, 4, 5 };
    // 二维数组
    int arr2D[3][4] = { {1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12} };
    // 普通 int 指针
    int x = 10;
    int* ptr = &x;

    //普通的和单个变量绑定引用 用于在语法上和下面其他引用对比
    int& refX = x;

    // 为一维数组声明引用别名
    int(&arr1)[5] = arr;//arr1一个别名了
    typedef int(&arrRef)[5];
    arrRef ref_arr = arr;//ref_arr是一个别名了

    // 为二维数组声明引用别名
    int(&arr2D1)[3][4] = arr2D;//arr2D1一个别名了
    typedef int(&arr2DRef)[3][4];
    arr2DRef ref_arr2D = arr2D;//ref_arr2D是一个别名了

    // 为普通 int 指针声明引用别名
    int*& ptrRef = ptr;

    // 输出元素验证
    cout << "一维数组引用元素: " << arr1[1] << endl;//2
    cout << "一维数组引用元素: " << ref_arr[2] << endl;//3
    cout << "二维数组引用元素: " << arr2D1[0][0] << endl;//1
    cout << "二维数组引用元素: " << ref_arr2D[1][1] << endl;//6
    cout << "指针引用元素: " << *ptrRef << endl;//10

    #pragma endregion

    #pragma region 练习题二 

    int bb = 22;
    addRef(bb);
    cout << bb << endl;//23

    #pragma endregion

    cout << "******************" << endl;

    #pragma region 练习题三

    int array[] = { 1,2,3,4,5 };

    /*int& value = changeArrayValue(array, 2);
    value = 99;*/
    changeArrayValue(array, 2) = 99;

    for (int i = 0; i < 5; i++)
    {
        cout << array[i] << endl;
    }
    // 1 2 99 4 5

    #pragma endregion

    cout << "******************" << endl;

    #pragma region 练习题四

    //对于 常量左值引用参数来说 不仅可以传入左值 也可以传入右值
    int cc = 666;
    test(cc);//666
    test(999);//999

    #pragma endregion
}

#pragma region 练习题一 

//请为一维数组、二维数组、指针
//声明一个引用别名

#pragma endregion

#pragma region 练习题二 

//编写一个函数,接收一个 int 类型的左值引用作为参数,将其值加1
//调用该函数后,验证原变量的值是否被修改

void addRef(int& value)
{
    value += 1;
}

#pragma endregion

#pragma region 练习题三 

//编写一个函数,返回一个数组中某个元素的左值引用,
//并通过该引用修改数组中元素的值

int& changeArrayValue(int array[], int index)
{
    return array[index];
}

#pragma endregion

#pragma region 练习题四 

//编写一个函数,使用 const 左值引用接收参数并打印参数值,确保函数能接受左值和右值

//对于 常量左值引用参数来说 不仅可以传入左值 也可以传入右值
void test(const int& value)
{
    cout << value << endl;
}

#pragma endregion


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com

×

喜欢就点赞,疼爱就打赏