C++函数参数的引用方式

简介: C++函数参数的引用方式

C++ 参数分类

在C++中,函数参数可以分为以下几种分类:

位置参数

位置参数是指按照定义的顺序传递给函数的参数。在函数调用时,实参的顺序必须与函数声明或定义中形参的顺序相对应。

示例代码

int add(int a, int b) {
    return a + b;
}
int main() {
    int result = add(5, 3);
    return 0;
}

在上述示例中,add 函数接收两个位置参数 ab,并返回它们的和。在函数调用 add(5, 3) 中,5被赋给了参数 a,3 被赋给了 参数 b

默认参数:

有默认值的参数,可以不传;一般刚在参数列表的最后;

默认参数是指在函数声明或定义时为参数提供默认值。如果函数调用时没有提供对应参数的值,则将使用默认值作为实参。

示例代码:

int multiply(int a, int b = 2) {
    return a * b;
}
int main() {
    int x = 5;
    int result1 = multiply(x);     // 使用默认参数,相当于 multiply(x, 2)
    int result2 = multiply(x, 3);  // 不使用默认参数,直接传递实参
    return 0;
}

在上面的示例中,multiply 函数的第二个参数 b 设置了默认值 2。在函数调用 multiply(x) 中,由于没有提供第二个参数的值,因此将使用默认值 2。而在函数调用 multiply(x, 3) 中,直接传递了实参 3。

可变参数(变参函数)

关键在于:参数数量可变;

可变参数是指函数可以接受数量可变的参数。在C++中,通过使用标准库中的可变参数模板 std::initializer_list 来实现可变参数的功能。

示例代码:

double average(std::initializer_list<double> nums) {
    double sum = 0;
    for (auto num : nums) {
        sum += num;
    }
    return sum / nums.size();
}
int main() {
    double avg1 = average({1.2, 2.4, 3.6});
    double avg2 = average({5.1, 6.2, 7.3, 8.4, 9.5});
    return 0;
}

上述示例中的 average 函数可以接受不定数量的 double 类型参数,并计算它们的平均值。在函数调用时,可以使用花括号 {} 来初始化 std::initializer_list 并传递参数。

借助不同的参数分类方式,可以提供更灵活和多样化的函数调用方式。

C++函数参数值传递和引用传递

常规分类

在 C++ 中,函数的参数传递方式可以分为值传递和引用传递。这两种方式在参数的传递方式和对实参的修改能力上有所不同。

值传递(Pass by Value):

值传递是指将实参的值复制给形参,在函数中对形参的修改不会影响实参本身。

示例代码:

void modifyValue(int num) {
    num = 10;
}
int main() {
    int x = 5;
    modifyValue(x);
    // x的值仍然是5,没有被修改
    return 0;
}

在上述示例中,modifyValue 函数使用值传递方式接收参数 num。在函数内部对 num 的修改不会影响到实参 x 的值。

使用值传递的特点:

  • 在函数中对参数进行修改不会影响原始的实参。
  • 函数会创建形参的副本,因此可能会占用额外的内存。
  • 可以避免函数对实参的修改,从而保持实参的不变性。

引用传递(Pass by Reference):

引用传递是指将实参的引用传递给形参,在函数中对形参的修改会同时修改实参。

示例代码:

void modifyValue(int& num) {
    num = 10;
}
int main() {
    int x = 5;
    modifyValue(x);
    // x的值被修改为10
    return 0;
}

在上述示例中,modifyValue 函数使用引用传递方式接收参数 num。在函数内部对 num 的修改也会反映到实参 x 上,使其值变为了 10。

使用引用传递的特点:

  • 函数可以直接修改实参的值,避免了值传递的额外内存开销。
  • 可以通过引用传递对象来避免对象的复制构造函数的调用,提高效率。
  • 如果希望通过函数修改实参的值,可以使用引用传递。

需要注意的是,使用引用传递时需要确保传递的参数不会过早地销毁,否则引用将指向无效的内存。

总结来说,值传递将实参的值复制给函数的形参,对形参的修改不会影响实参本身;引用传递将实参的引用传递给函数的形参,对形参的修改会同时修改实参。

C++ 引用参数的分类

在C++中,引用传递又可以根据是否具有 const 限定符进行分类。引用参数的分类如下:

非常量引用参数

可变的引用参数;

非常量引用参数是使用 & 符号定义的,它允许函数修改传递给它的实参,并且对应的实参也会被修改。

示例代码:

void changeValue(int& num) {
    num = 10;
}
int main() {
    int x = 5;
    changeValue(x);
    // x的值被修改为10
    return 0;
}

在上述示例中,changeValue 函数的参数 num 是一个非常量引用。在函数内部对 num 的修改直接反映到了实参 x 上,使得其值变为了 10。

使用非常量引用参数的场景:

  • 当函数需要修改传递进来的参数的值时。
  • 当将大型对象作为参数传递给函数时,通过引用传递可以避免对象的复制。

常量引用参数(不可变的应用参数)

常量引用参数是使用 const 关键字和 & 符号定义的,它确保函数无法修改传递给它的实参,只能读取。

示例代码:

void printValue(const int& num) {
    std::cout << "Value: " << num << std::endl;
}
int main() {
    int x = 5;
    printValue(x);
    return 0;
}

在上述示例中,printValue 函数的参数 num 是一个常量引用。函数内部无法修改 num 的值,只能读取。因此,printValue 函数只会打印实参 x 的值,不会对实参进行修改。

使用常量引用参数的场景:

  • 当函数不需要修改传递进来的参数的值时,可以避免不必要的变动。
  • 当将大型对象作为参数传递给函数时,通过常量引用传递可以避免对象的复制,并提高效率。

非常量引用参数允许修改传递给函数的实参,而常量引用参数只能读取实参的值,不能进行修改。选择哪种引用参数取决于函数是否需要修改实参的值。

C++参数引用的方法分类

在 C++ 中,参数引用还可以可以根据语法和修改能力进行分类。以下是几种常见的参数引用方法分类:

左值引用(Lvalue references):

左值引用使用 & 符号定义,在函数参数列表中表示对传递给函数的变量进行引用。该引用可以修改传递给函数的变量。

示例代码:

void changeValue(int& num) {
    num = 10;
}
int main() {
    int x = 5;
    changeValue(x);
    // x的值被修改为10
    return 0;
}

在上述示例中,changeValue 函数的参数 num 是一个左值引用。通过引用传递,函数可以修改实参 x 的值,将其更改为 10。

常量左值引用(Const Lvalue references):

常量左值引用使用 const 关键字和 & 符号定义,允许函数引用传递给它们的变量,并且可以读取但不能修改这些变量的值。

示例代码:

void printValue(const int& num) {
    std::cout << "Value: " << num << std::endl;
}
int main() {
    int x = 5;
    printValue(x);
    return 0;
}

在上述示例中,printValue 函数的参数 num 是一个常量左值引用。函数可以引用传递的实参 x,但只能读取它的值,不能修改。

右值引用(Rvalue references):

右值引用使用 && 符号定义,允许将右值绑定到引用上。右值引用通常用于实现移动语义和完美转发。

示例代码:

void changeValue(int&& num) {
    num = 10;
}
int main() {
    int x = 5;
    changeValue(std::move(x));
    // 此时x的值是未定义的
    return 0;
}

在上述示例中,changeValue 函数的参数 num 是一个右值引用。通过使用 std::move 将左值 x 转换为右值引用传递给函数,然后在函数内部修改了该值。

关注我,不迷路,共学习,同进步

关注我,不迷路,共学习,同进步

相关文章
|
1月前
|
程序员 C++ 容器
在 C++中,realloc 函数返回 NULL 时,需要手动释放原来的内存吗?
在 C++ 中,当 realloc 函数返回 NULL 时,表示内存重新分配失败,但原内存块仍然有效,因此需要手动释放原来的内存,以避免内存泄漏。
|
1月前
|
存储 前端开发 C++
C++ 多线程之带返回值的线程处理函数
这篇文章介绍了在C++中使用`async`函数、`packaged_task`和`promise`三种方法来创建带返回值的线程处理函数。
46 6
|
1月前
|
C++
C++ 多线程之线程管理函数
这篇文章介绍了C++中多线程编程的几个关键函数,包括获取线程ID的`get_id()`,延时函数`sleep_for()`,线程让步函数`yield()`,以及阻塞线程直到指定时间的`sleep_until()`。
25 0
C++ 多线程之线程管理函数
|
1月前
|
编译器 C语言 C++
C++入门3——类与对象2-2(类的6个默认成员函数)
C++入门3——类与对象2-2(类的6个默认成员函数)
24 3
|
1月前
|
编译器 C语言 C++
详解C/C++动态内存函数(malloc、free、calloc、realloc)
详解C/C++动态内存函数(malloc、free、calloc、realloc)
174 1
|
1月前
|
存储 编译器 C++
C++入门3——类与对象2-1(类的6个默认成员函数)
C++入门3——类与对象2-1(类的6个默认成员函数)
33 1
|
1月前
|
编译器 C语言 C++
C++入门6——模板(泛型编程、函数模板、类模板)
C++入门6——模板(泛型编程、函数模板、类模板)
42 0
C++入门6——模板(泛型编程、函数模板、类模板)
|
1月前
|
算法 编译器 C++
【C++篇】领略模板编程的进阶之美:参数巧思与编译的智慧
【C++篇】领略模板编程的进阶之美:参数巧思与编译的智慧
79 2
|
2月前
|
编译器 C++
【C++核心】函数的应用和提高详解
这篇文章详细讲解了C++函数的定义、调用、值传递、常见样式、声明、分文件编写以及函数提高的内容,包括函数默认参数、占位参数、重载等高级用法。
23 3
|
3月前
|
编译器 C++ 容器
【C++】String常见函数用法
【C++】String常见函数用法