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 转换为右值引用传递给函数,然后在函数内部修改了该值。

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

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

相关文章
|
2天前
|
存储 C++
【C++】string类的使用③(非成员函数重载Non-member function overloads)
这篇文章探讨了C++中`std::string`的`replace`和`swap`函数以及非成员函数重载。`replace`提供了多种方式替换字符串中的部分内容,包括使用字符串、子串、字符、字符数组和填充字符。`swap`函数用于交换两个`string`对象的内容,成员函数版本效率更高。非成员函数重载包括`operator+`实现字符串连接,关系运算符(如`==`, `&lt;`等)用于比较字符串,以及`swap`非成员函数。此外,还介绍了`getline`函数,用于按指定分隔符从输入流中读取字符串。文章强调了非成员函数在特定情况下的作用,并给出了多个示例代码。
|
10天前
|
C++
C++引用
C++引用
6 1
|
2天前
|
C++
C++基础知识(二:引用和new delete)
引用是C++中的一种复合类型,它是某个已存在变量的别名,也就是说引用不是独立的实体,它只是为已存在的变量取了一个新名字。一旦引用被初始化为某个变量,就不能改变引用到另一个变量。引用的主要用途包括函数参数传递、操作符重载等,它可以避免复制大对象的开销,并且使得代码更加直观易读。
|
3天前
|
算法 C++ 容器
|
3天前
|
存储 编译器 程序员
|
4天前
|
存储 自然语言处理 编译器
|
4天前
|
存储 编译器 文件存储
|
4天前
|
安全 C++
|
7天前
|
编译器 C++
【C++】类和对象③(类的默认成员函数:赋值运算符重载)
在C++中,运算符重载允许为用户定义的类型扩展运算符功能,但不能创建新运算符如`operator@`。重载的运算符必须至少有一个类类型参数,且不能改变内置类型运算符的含义。`.*::sizeof?`不可重载。赋值运算符`=`通常作为成员函数重载,确保封装性,如`Date`类的`operator==`。赋值运算符应返回引用并检查自我赋值。当未显式重载时,编译器提供默认实现,但这可能不足以处理资源管理。拷贝构造和赋值运算符在对象复制中有不同用途,需根据类需求定制实现。正确实现它们对避免数据错误和内存问题至关重要。接下来将探讨更多操作符重载和默认成员函数。