C++函数及应用

C++函数初相识

函数是C++ 编程的基础模块,它可以将一段独立的功能代码封装起来,通过定义好的接口进行调用,提高了代码的复用性和可维护性 。​

函数能将复杂的任务分解成一个个独立的模块,每个模块负责完成特定的功能,使得程序结构清晰,便于管理和维护。例如在一个大型游戏开发项目中,角色的移动、攻击、防御等功能都可以封装成不同的函数。当需要实现角色的某个行为时,直接调用相应的函数即可,而不需要每次都重复编写实现该行为的代码。

函数定义

一个完整的C++函数定义包括以下几个部分:返回类型、函数名、参数列表和函数体。下面来看一个简单的加法函数示例:​​

// 返回类型为int,表示函数返回一个整数​
// 函数名为add​
// 参数列表包含两个int类型的参数a和b​
int add(int a, int b) {​
    // 函数体:执行加法操作并返回结果​
    return a + b;​
}​

在这个例子中,int是返回类型,它告诉编译器这个函数最终会返回一个整数。add是函数名,这是调用这个函数时使用的标识符,(int a, int b)是参数列表,该函数定义了两个int类型的参数a和b,它们是函数执行加法运算所需要的操作数。函数体{ return a + b; }实现加法功能的具体代码,并通过return语句返回计算结果 。

函数参数传递

值传递

值传递就像是你有一份重要的文件(实参),当你要交给别人(函数)处理时,你并不直接把原件给他,而是先复印一份(副本),然后把复印件交给对方。对方在复印件上进行任何修改(修改形参),都不会影响到你手中的原件(实参)。​

下面来看一个交换两个整数的函数示例:​​

void swapValues(int a, int b) {​
    int temp = a;​
    a = b;​
    b = temp;​
}​

在这个函数中,a和b是通过值传递接收实参值的副本。当外部调用swapValues函数时,例如swapValues(x, y),x和y的值会被复制给a和b,在函数内部交换a和b的值,并不会影响到x和y在函数外部的实际值。

引用传递

引用传递则像是你给别人一个指向你文件的快捷方式(引用),别人通过这个快捷方式直接访问和修改你的文件(实参)。也就是说,引用传递时,函数接收的是实参的别名,对形参的任何修改都会直接反映在实参上。​

还是以上面的交换函数为例,使用引用传递来实现:​​

void swapReferences(int& a, int& b) {​
    int temp = a;​
    a = b;​
    b = temp;​
}​

这里的int& a和int& b表示a和b是引用类型的参数,它们分别是实参的别名。当调用swapReferences(x, y)时,a和b就分别成为了x和y的别名,在函数内部对a和b的操作,实际上就是对x和y的操作,所以能够真正交换x和y的值。

指针传递​

指针传递就像是你把文件的存放地址(指针)告诉别人,别人可以通过这个地址找到并访问你的文件(实参)。在指针传递中,函数接收的是一个指针,该指针指向实参的内存地址,通过操作指针,可以间接修改实参的值。​

下面是使用指针传递实现交换函数的代码:​​

void swapPointers(int* a, int* b) {​
    int temp = *a;​
    *a = *b;​
    *b = temp;​
}​

在这个函数中,int* a和int* b表示a和b是指针类型的参数,它们存储的是实参的内存地址。当调用swapPointers(&x, &y)时(这里的&是取地址运算符,用于获取x和y的地址),a和b分别指向x和y的内存地址,通过解引用指针(*a和*b),可以访问并修改x和y的值,从而实现交换功能 。

函数声明与调用

函数声明让编译器知道这个函数的基本信息,包括函数名、返回类型和参数列表。当编译器在后续代码中遇到函数调用时,能够顺利地进行编译工作。函数声明的语法和函数定义的头部类似,只是不需要包含函数体,例如:​​

// 函数声明​

int add(int a, int b);​​

当程序执行到函数调用语句时,会按照函数定义的逻辑执行相应的代码。调用函数时,需要提供与函数参数列表匹配的实参,实参的数量、类型和顺序都要与形参一致。例如,对于前面定义的add函数,可以这样调用:​​

int result = add(3, 5);​​

在这个例子中,add(3, 5)就是函数调用表达式,3和5是实参,它们会按照顺序分别传递给add函数的形参a和b。函数执行完毕后,返回的结果会赋值给result变量。

函数的重载

函数重载允许在同一作用域内定义多个同名的函数,不过这些函数的参数列表(包括参数的数量、类型或顺序)必须有所不同。​

例如,在开发一个数学计算库时,经常会遇到需要实现不同类型数据相加的功能。如果没有函数重载,可能需要为每种数据类型分别定义不同的函数名,像addInt用于整数相加,addDouble用于双精度浮点数相加等等,这样不仅函数名繁多,而且代码的可读性和维护性较差。通过函数重载,可以定义多个名为add的函数,分别处理不同类型的数据。​

// 处理两个整数相加​
int add(int a, int b) {​
    return a + b;​
}​

// 处理两个双精度浮点数相加​
double add(double a, double b) {​
    return a + b;​
}​
// 处理一个整数和一个双精度浮点数相加​
double add(int a, double b) {​
    return a + b;​
}​

在调用上述函数时,编译器会根据实参的类型和数量,自动匹配最合适的函数版本。例如:​​

int result1 = add(3, 5); // 调用int add(int a, int b)​
double result2 = add(3.5, 5.5); // 调用double add(double a, double b)​
double result3 = add(3, 5.5); // 调用double add(int a, double b)​

注意:函数的返回类型不能作为函数重载的依据。也就是说,仅仅返回类型不同,而参数列表相同的两个函数,是不能构成函数重载的。下面函数重载的代码是错误的:​

// 错误示例:仅返回类型不同,不能构成函数重载​
int add(int a, int b) {​
    return a + b;​
}​
double add(int a, int b) {​
    return a + b;​
}​

编译器在编译时,无法根据函数调用语句add(3, 5)来确定到底应该调用哪个函数,这就会导致编译错误。因此在使用函数重载时,一定要确保参数列表有明显的区别,这样才能让编译器匹配到正确的函数版本。

默认参数

默认参数允许在定义函数时,为参数指定一个默认值。这样,在调用函数时,如果没有为该参数传递具体的值,编译器就会自动使用默认值 。​

假设你正在编写一个发送邮件的函数,其中有一个参数是邮件的优先级。在大多数情况下,我们可能希望邮件以普通优先级发送,只有在特殊情况下才需要指定更高或更低的优先级。这时,就可以使用默认参数来简化函数调用。​​

// 定义发送邮件的函数,priority参数有默认值1(表示普通优先级)​
void sendEmail(const std::string& recipient, const std::string& content, int priority = 1) {​
    // 函数体:实现发送邮件的逻辑​
    std::cout << "Sending email to " << recipient << " with content: " << content;​
    if (priority != 1) {​
        std::cout << " and priority " << priority;​
    }​
    std::cout << std::endl;​
}​

在调用这个函数时,可以根据实际需求选择是否传递priority参数:​

// 调用函数,使用默认优先级​

sendEmail("example@example.com", "Hello, this is a test email.");​

// 调用函数,指定优先级为3​

sendEmail("another@example.com", "Important notice!", 3);​

使用默认参数时,也有一些规则需要遵循。首先,有默认值的参数必须从右至左连续排列,也就是说,一旦某个参数有了默认值,它右边的所有参数都必须有默认值。例如:​

// 正确示例​
void func(int a, int b = 2, int c = 3) {​
    // 函数体​
}​
// 错误示例​
void wrongFunc(int a = 1, int b, int c = 3) {​
    // 函数体,b没有默认值,不符合规则​
}​

默认参数只能出现在函数声明中,不能同时出现在声明和定义中。​

// 函数声明,指定默认参数​
void printInfo(const std::string& name, int age = 18);​

// 函数定义,不能再指定默认参数​
void printInfo(const std::string& name, int age) {​
    std::cout << "Name: " << name << ", Age: " << age << std::endl;​
}​

简单计算器

这个计算器将具备加、减、乘、除四种基本运算功能,通过用户输入选择运算类型,并输入相应的操作数来进行计算。​

首先定义四个函数分别实现加、减、乘、除运算:​

// 加法函数​
double add(double a, double b) {​
    return a + b;​
}​

// 减法函数​
double subtract(double a, double b) {​
    return a - b;​
}​
// 乘法函数​

double multiply(double a, double b) {​

    return a * b;​

}​

// 除法函数​

double divide(double a, double b) {​
    if (b == 0) {​
        // 处理除零错误​
        std::cerr << "Error: Division by zero!" << std::endl;​
        return 0;​
    }​    return a / b;​

}​

​

然后,在main函数中,获取用户的输入,并根据用户选择的运算符调用相应的函数进行计算:​

#include <iostream>​
int main() {​
    double num1, num2;​
    char operator;​
    std::cout << "请输入第一个数字: ";​
    std::cin >> num1;​
    std::cout << "请输入运算符 (+, -, *, /): ";​
    std::cin >> operator;​
    std::cout << "请输入第二个数字: ";​
    std::cin >> num2;​
    double result;​
    switch (operator) {​
        case '+':​

            result = add(num1, num2);​

            break;​

        case '-':​

            result = subtract(num1, num2);​

            break;​

        case '*':​

            result = multiply(num1, num2);​

            break;​

        case '/':​

            result = divide(num1, num2);​

            break;​

        default:​

            std::cerr << "错误: 无效的运算符" << std::endl;​

            return 1;​

    }​

    std::cout << "计算结果是: " << result << std::endl;​

    return 0;​

}​

在这段代码中,add、subtract、multiply和divide函数分别实现了加法、减法、乘法和除法运算。在main函数中,首先提示用户输入两个数字和一个运算符,然后根据运算符使用switch语句调用相应的函数进行计算,并输出结果。如果用户输入的运算符无效,程序会输出错误信息并终止;如果用户尝试除以零,除法函数会输出错误提示并返回 0 。通过这个简单的计算器案例,可以看到函数是如何将复杂的计算任务分解为独立的模块,使代码结构更加清晰,易于理解和维护 。

发表评论

滚动至顶部
0

Subtotal