C++基础知识之函数1

电子说

1.3w人已加入

描述

函数是 C++ 中的一个重要概念,它可以让我们将一段代码封装起来,然后在需要的时候调用它。C++ 中的函数有以下几个特点:

  • 函数可以有参数和返回值。
  • 函数可以被其他函数调用。
  • 函数可以被重载,即可以定义多个同名的函数,只要它们的参数列表不同即可。

函数的定义和调用

在 C++ 中,函数的定义和调用都非常简单。以下是一个简单的函数的定义和调用的示例:

#include 

// 定义一个名为 add 的函数,它有两个参数 x 和 y,返回值为 x + y
int add(int x, int y) {
    return x + y;
}

int main() {
    // 调用 add 函数,并将返回值赋值给变量 z
    int z = add(1, 2);
    std::cout << "1 + 2 = " << z << std::endl;
    return 0;
}

在这个示例中,我们定义了一个名为 add 的函数,它有两个参数 x 和 y,返回值为 x + y。然后在 main 函数中,我们调用了 add 函数,并将返回值赋值给变量 z,最后输出了 1 + 2 = 3。

函数的参数和返回值

在 C++ 中,函数可以有参数和返回值。以下是一个带有参数和返回值的函数的示例:

#include 

// 定义一个名为 add 的函数,它有两个参数 x 和 y,返回值为 x + y
int add(int x, int y) {
    return x + y;
}

int main() {
    // 调用 add 函数,并将返回值赋值给变量 z
    int z = add(1, 2);
    std::cout << "1 + 2 = " << z <<
    std::endl;

// 调用 add 函数,并将返回值赋值给变量 z
}

在这个示例中,我们定义了一个名为 add 的函数,它有两个参数 x 和 y,返回值为 x + y。然后在 main 函数中,我们调用了 add 函数两次,并将返回值分别赋值给变量 z,最后输出了 1 + 2 = 3 和 3 + 4 = 7。

函数的重载

在 C++ 中,函数可以被重载,即可以定义多个同名的函数,只要它们的参数列表不同即可。以下是一个函数重载的示例:

#include 

// 定义一个名为 add 的函数,它有两个参数 x 和 y,返回值为 x + y
int add(int x, int y) {
    return x + y;
}

// 定义一个名为 add 的函数,它有三个参数 x、y 和 z,返回值为 x + y + z
int add(int x, int y, int z) {
    return x + y + z;
}

int main() {
    // 调用 add 函数,并将返回值赋值给变量 z
    int z = add(1, 2);
    std::cout << "1 + 2 = " << z << std::endl;

    // 调用 add 函数,并将返回值赋值给变量 z
    z = add(1, 2, 3);
    std::cout << "1 + 2 + 3 = " << z << std::endl;

    return 0;
}

在这个示例中,我们定义了两个同名的函数 add,它们的参数列表不同。这就是函数重载的一个例子。函数重载可以让我们定义多个同名的函数,只要它们的参数列表不同即可。这样可以让我们更方便地使用函数,而不需要为每个函数取不同的名字。

参数传递

在 C++ 中,函数的参数传递有两种方式:值传递和引用传递。

值传递

值传递是指将参数的值复制一份,然后将这份复制传递给函数。在函数内部,对参数的修改不会影响到原始的参数。以下是一个值传递的示例:

#include 

// 定义一个名为 add 的函数,它有两个参数 x 和 y,返回值为 x + y
int add(int x, int y) {
    x = x + 1;
    y = y + 1;
    return x + y;
}

int main() {
    int a = 1;
    int b = 2;
    int c = add(a, b);
    std::cout << "a = " << a << std::endl; // 输出 a = 1
    std::cout << "b = " << b << std::endl; // 输出 b = 2
    std::cout << "c = " << c << std::endl; // 输出 c = 5
    return 0;
}

在这个示例中,我们定义了一个名为 add 的函数,它有两个参数 x 和 y,返回值为 x + y。然后在 main 函数中,我们定义了三个变量 a、b 和 c,并将 a 和 b 的值分别赋为 1 和 2。然后我们调用了 add 函数,并将 a 和 b 作为参数传递给它。在 add 函数内部,我们对 x 和 y 的值进行了修改,但是这些修改不会影响到 a 和 b 的值。

引用传递

引用传递是指将参数的引用传递给函数。在函数内部,对参数的修改会影响到原始的参数。以下是一个引用传递的示例:

#include 

// 定义一个名为 add 的函数,它有两个参数 x 和 y,返回值为 x + y
int add(int& x, int& y) {
    x = x + 1;
    y = y + 1;
    return x + y;
}

int main() {
    int a = 1;
    int b = 2;
    int c = add(a, b);
    std::cout << "a = " << a << std::endl; // 输出 a = 2
    std::cout << "b = " << b << std::endl; // 输出 b = 3
    std::cout << "c = " << c << std::endl; // 输出 c = 6
    return 0;
}

在这个示例中,我们定义了一个名为 add 的函数,它有两个参数 x 和 y,返回值为 x + y。然后在 main 函数中,我们定义了三个变量 a、b 和 c,并将 a 和 b 的值分别赋为 1 和 2。然后我们调用了 add 函数,并将 a 和 b 的引用作为参数传递给它。在 add 函数内部,我们对 x 和 y 的值进行了修改,这些修改会影响到 a 和 b 的值。

选择哪种方式

在选择参数传递方式时,需要考虑以下几个因素:

  • 如果参数是一个较小的基本类型(如 int、double 等),可以使用值传递。
  • 如果参数是一个较大的结构体或类,可以使用引用传递,这样可以避免复制大量的数据。
  • 如果需要在函数内部修改参数的值,并且希望这些修改能够影响到原始的参数,可以使用引用传递。

函数匹配

在C++中,函数匹配是指编译器在调用函数时,根据实参的类型和数量,从函数的重载集合中选择一个最佳的匹配函数的过程。函数匹配是C++中的一个重要概念,它决定了程序调用哪个函数,因此对于C++程序员来说,了解函数匹配的规则和原理是非常重要的。C++中的函数匹配规则比较复杂,主要包括以下几个方面:

  • 实参类型的精确匹配
  • 实参类型的标准类型转换
  • 实参类型的用户自定义类型转换
  • 函数模板的匹配
实参类型的精确匹配

如果函数的形参类型和实参类型完全一致,那么这个函数就是一个精确匹配。例如,下面的代码中,foo函数的形参类型和实参类型完全一致,因此它是一个精确匹配:

void foo(int x, double y) {
    // ...
}

int main() {
    int a = 1;
    double b = 2.0;
    foo(a, b); // 精确匹配
    return 0;
}
实参类型的标准类型转换

如果函数的形参类型和实参类型不一致,但是可以通过标准类型转换(如整型提升、算术类型转换、指针类型转换等)将实参类型转换为形参类型,那么这个函数就是一个标准类型转换匹配。 实例如,下面的代码中,foo函数的形参类型是int, 而实参类型是short,但是可以通过整型提升将short类型转换为int类型,因此foo函数是一个标准类型转换匹配:

void foo(int x, double y) {
    // ...
}

int main() {
    short a = 1;
    double b = 2.0;
    foo(a, b); // 标准类型转换匹配
    return 0;
}
实参类型的用户自定义类型转换

如果函数的形参类型和实参类型不一致,且不能通过标准类型转换将实参类型转换为形参类型,但是可以通过用户自定义类型转换将实参类型转换为形参类型,那么这个函数就是一个用户自定义类型转换匹配。例如,下面的代码中,foo函数的形参类型是double,而实参类型是int,但是可以通过用户自定义类型转换将int类型转换为double类型,因此foo函数是一个用户自定义类型转换匹配:

class A {
public:
    operator double() const {
        return 0.0;
    }
};

void foo(double x) {
    // ...
}

int main() {
    A a;
    foo(a); // 用户自定义类型转换匹配
    return 0;
}

在上面的例子中,foo函数的形参类型是double,而实参类型是A,但是可以通过用户自定义类型转换将A类型转换为double类型。具体来说,A类定义了一个类型转换函数operator double(),该函数将A类型转换为double类型。当我们调用foo函数时,编译器会自动调用A类的类型转换函数,将A类型转换为double类型,然后将转换后的double类型作为实参传递给foo函数。

函数模版匹配

在C++中,函数模板匹配是通过模板参数推导来实现的。当我们调用一个函数模板时,编译器会根据实参的类型推导出模板参数的类型,然后根据模板参数的类型来匹配函数模板。具体来说,编译器会根据实参的类型推导出模板参数的类型,然后将模板参数的类型与函数模板的形参类型进行匹配。如果匹配成功,则使用该函数模板来生成对应的函数实例;否则,编译器会报错。

❝需要注意的是,函数模板匹配是一种非常灵活的机制,它可以根据实参的类型来推导出模板参数的类型,从而实现类型自动推导。但是,由于函数模板匹配是在编译时进行的,因此需要满足一定的语法规则和限制。例如,函数模板的形参类型不能是引用类型,否则会导致模板参数推导失败;函数模板的形参类型不能是void类型,否则会导致编译错误等。 下面是一个函数模板匹配的例子:

template <typename T>
void foo(T x) {
    std::cout << x << std::endl;
}

int main() {
    foo(1); // T = int
    foo(1.0); // T = double
    foo("hello"); // T = const char*
    return 0;
}

在上面的代码中,我们定义了一个函数模板foo,它有一个模板参数T和一个形参x。当我们调用foo函数时,编译器会根据实参的类型推导出模板参数的类型,然后将模板参数的类型与函数模板的形参类型进行匹配。例如,当我们调用foo(1)时,编译器会推导出T为int,从而使用foo来生成对应的函数实例。当我们调用foo(1.0)时,编译器会推导出T为double,从而使用foo来生成对应的函数实例。当我们调用foo("hello")时,编译器会推导出T为const char,从而使用foo来生成对应的函数实例。

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分