Skip to content

函数

函数是C++程序的基本组成单位,用于实现特定功能的代码块。通过函数可以将程序分解为多个模块,提高代码的可读性和复用性。本章将详细介绍C++函数的定义和使用。

函数基础

函数的定义

cpp
#include <iostream>
using namespace std;

// 函数声明(原型)
int add(int a, int b);      // 声明但不定义
int multiply(int, int);     // 声明时参数名可省略

// 函数定义
// 返回类型 函数名(参数列表) { 函数体 }
int add(int a, int b) {
    return a + b;  // 返回两个数的和
}

// 无返回值的函数
void printHello() {
    cout << "Hello, C++!" << endl;
    // void函数不需要return语句
    // 或者使用 return; 提前返回
}

// 无参数的函数
int getRandomNumber() {
    return 42;  // 返回一个固定值
}

int main() {
    // 调用函数
    int result = add(10, 20);
    cout << "10 + 20 = " << result << endl;
    
    // 调用无返回值函数
    printHello();
    
    // 调用无参数函数
    int num = getRandomNumber();
    cout << "随机数: " << num << endl;
    
    return 0;
}

// 函数定义可以放在main之后
int multiply(int a, int b) {
    return a * b;
}

函数参数

cpp
#include <iostream>
using namespace std;

// ============ 值传递 ============

// 值传递:函数内部修改不影响原变量
void incrementValue(int x) {
    x++;  // 修改的是副本
    cout << "函数内 x = " << x << endl;
}

// ============ 引用传递 ============

// 引用传递:函数内部修改会影响原变量
void incrementRef(int& x) {
    x++;  // 修改的是原变量
    cout << "函数内 x = " << x << endl;
}

// ============ 指针传递 ============

// 指针传递:通过指针修改原变量
void incrementPtr(int* x) {
    (*x)++;  // 通过解引用修改
    cout << "函数内 *x = " << *x << endl;
}

// ============ 常量引用 ============

// 常量引用:避免拷贝,但不能修改
void printString(const string& str) {
    cout << str << endl;
    // str = "new";  // 错误:不能修改const引用
}

int main() {
    int a = 10;
    
    // 值传递
    cout << "===== 值传递 =====" << endl;
    cout << "调用前 a = " << a << endl;
    incrementValue(a);
    cout << "调用后 a = " << a << endl;  // a不变
    
    // 引用传递
    cout << "\n===== 引用传递 =====" << endl;
    a = 10;
    cout << "调用前 a = " << a << endl;
    incrementRef(a);
    cout << "调用后 a = " << a << endl;  // a改变了
    
    // 指针传递
    cout << "\n===== 指针传递 =====" << endl;
    a = 10;
    cout << "调用前 a = " << a << endl;
    incrementPtr(&a);
    cout << "调用后 a = " << a << endl;  // a改变了
    
    // 常量引用
    cout << "\n===== 常量引用 =====" << endl;
    string message = "Hello";
    printString(message);
    
    return 0;
}

默认参数

cpp
#include <iostream>
using namespace std;

// 默认参数:从右向左提供
// 有默认值的参数必须放在参数列表末尾

// 正确:默认参数在右边
int power(int base, int exp = 2) {
    int result = 1;
    for (int i = 0; i < exp; i++) {
        result *= base;
    }
    return result;
}

// 正确:多个默认参数
void printInfo(string name, int age = 18, string city = "北京") {
    cout << "姓名: " << name << endl;
    cout << "年龄: " << age << endl;
    cout << "城市: " << city << endl;
}

// 错误示例:默认参数不能在非默认参数之前
// int wrong(int a = 1, int b);  // 错误!

int main() {
    // 使用默认参数
    cout << "power(3) = " << power(3) << endl;      // 3^2 = 9
    cout << "power(3, 3) = " << power(3, 3) << endl;  // 3^3 = 27
    
    // 多个默认参数
    cout << "\n===== 使用默认参数 =====" << endl;
    printInfo("张三");  // 使用所有默认值
    
    cout << "\n===== 部分使用默认参数 =====" << endl;
    printInfo("李四", 25);  // city使用默认值
    
    cout << "\n===== 不使用默认参数 =====" << endl;
    printInfo("王五", 30, "上海");  // 不使用默认值
    
    return 0;
}

函数重载

cpp
#include <iostream>
#include <string>
using namespace std;

// ============ 函数重载 ============

// 同名函数,参数不同(类型、数量、顺序)

// 计算两个整数的和
int add(int a, int b) {
    return a + b;
}

// 计算三个整数的和
int add(int a, int b, int c) {
    return a + b + c;
}

// 计算两个浮点数的和
double add(double a, double b) {
    return a + b;
}

// 计算整数和浮点数的和
double add(int a, double b) {
    return a + b;
}

// 计算浮点数和整数的和
double add(double a, int b) {
    return a + b;
}

// 连接两个字符串
string add(string a, string b) {
    return a + b;
}

int main() {
    // 根据参数类型和数量自动选择正确的函数
    cout << "add(1, 2) = " << add(1, 2) << endl;
    cout << "add(1, 2, 3) = " << add(1, 2, 3) << endl;
    cout << "add(1.5, 2.5) = " << add(1.5, 2.5) << endl;
    cout << "add(1, 2.5) = " << add(1, 2.5) << endl;
    cout << "add(1.5, 2) = " << add(1.5, 2) << endl;
    cout << "add(\"Hello\", \"World\") = " << add("Hello", "World") << endl;
    
    // 重载解析歧义
    // add(1, 2);  // 可能匹配多个函数
    
    return 0;
}

内联函数

cpp
#include <iostream>
using namespace std;

// ============ 内联函数 ============

// inline关键字建议编译器内联展开
// 避免函数调用的开销

// 定义内联函数
inline int square(int x) {
    return x * x;
}

// 内联函数适合短小的函数
inline int max(int a, int b) {
    return (a > b) ? a : b;
}

// 内联函数可以定义在头文件中
inline void printMessage(const char* msg) {
    cout << msg << endl;
}

// 注意:复杂的函数不适合内联
// 递归函数不能内联
// inline int factorial(int n) {
//     if (n <= 1) return 1;
//     return n * factorial(n - 1);  // 递归,无法内联
// }

int main() {
    // 内联函数调用
    int result = square(5);  // 编译器可能展开为: int result = 5 * 5;
    cout << "square(5) = " << result << endl;
    
    int m = max(10, 20);
    cout << "max(10, 20) = " << m << endl;
    
    printMessage("Hello, inline!");
    
    // 内联函数与宏的区别
    // 宏是文本替换,没有类型检查
    // 内联函数是真正的函数,有类型检查
    
    #define SQUARE_MACRO(x) ((x) * (x))
    
    int x = 5;
    
    // 宏的问题
    cout << "\n宏: SQUARE_MACRO(x++) = " << SQUARE_MACRO(x++) << endl;  // x被自增两次
    // x现在是7
    
    x = 5;
    // 内联函数安全
    cout << "内联: square(x++) = " << square(x++) << endl;  // x只被自增一次
    
    return 0;
}

递归函数

cpp
#include <iostream>
using namespace std;

// ============ 递归函数 ============

// 递归:函数调用自身

// 计算阶乘
long long factorial(int n) {
    // 基本情况(终止条件)
    if (n <= 1) {
        return 1;
    }
    // 递归情况
    return n * factorial(n - 1);
}

// 计算斐波那契数
long long fibonacci(int n) {
    if (n <= 0) return 0;
    if (n == 1) return 1;
    return fibonacci(n - 1) + fibonacci(n - 2);
}

// 计算幂
long long power(int base, int exp) {
    if (exp == 0) return 1;
    if (exp == 1) return base;
    return base * power(base, exp - 1);
}

// 快速幂(更高效)
long long fastPower(int base, int exp) {
    if (exp == 0) return 1;
    if (exp == 1) return base;
    
    long long half = fastPower(base, exp / 2);
    
    if (exp % 2 == 0) {
        return half * half;
    } else {
        return half * half * base;
    }
}

// 汉诺塔问题
void hanoi(int n, char from, char to, char aux) {
    if (n == 1) {
        cout << "移动盘子 1 从 " << from << " 到 " << to << endl;
        return;
    }
    
    hanoi(n - 1, from, aux, to);
    cout << "移动盘子 " << n << " 从 " << from << " 到 " << to << endl;
    hanoi(n - 1, aux, to, from);
}

// 二分查找(递归版本)
int binarySearch(int arr[], int left, int right, int target) {
    if (left > right) {
        return -1;  // 未找到
    }
    
    int mid = left + (right - left) / 2;
    
    if (arr[mid] == target) {
        return mid;
    } else if (arr[mid] < target) {
        return binarySearch(arr, mid + 1, right, target);
    } else {
        return binarySearch(arr, left, mid - 1, target);
    }
}

int main() {
    // 阶乘
    cout << "===== 阶乘 =====" << endl;
    for (int i = 0; i <= 10; i++) {
        cout << i << "! = " << factorial(i) << endl;
    }
    
    // 斐波那契数列
    cout << "\n===== 斐波那契数列 =====" << endl;
    for (int i = 0; i <= 15; i++) {
        cout << "fib(" << i << ") = " << fibonacci(i) << endl;
    }
    
    // 幂运算
    cout << "\n===== 幂运算 =====" << endl;
    cout << "2^10 = " << power(2, 10) << endl;
    cout << "2^10 (快速幂) = " << fastPower(2, 10) << endl;
    
    // 汉诺塔
    cout << "\n===== 汉诺塔 (3个盘子) =====" << endl;
    hanoi(3, 'A', 'C', 'B');
    
    // 二分查找
    int arr[] = {1, 3, 5, 7, 9, 11, 13, 15};
    int target = 7;
    int index = binarySearch(arr, 0, 7, target);
    cout << "\n===== 二分查找 =====" << endl;
    cout << "查找 " << target << ": 索引 = " << index << endl;
    
    return 0;
}

Lambda表达式

cpp
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
using namespace std;

int main() {
    // ============ Lambda表达式语法 ============
    
    // [捕获列表](参数列表) -> 返回类型 { 函数体 }
    
    // 最简单的lambda
    auto sayHello = []() {
        cout << "Hello, Lambda!" << endl;
    };
    sayHello();
    
    // 带参数的lambda
    auto add = [](int a, int b) {
        return a + b;
    };
    cout << "add(10, 20) = " << add(10, 20) << endl;
    
    // 显式指定返回类型
    auto divide = [](double a, double b) -> double {
        if (b == 0) return 0;
        return a / b;
    };
    cout << "divide(10, 3) = " << divide(10, 3) << endl;
    
    
    // ============ 捕获列表 ============
    
    int x = 10;
    int y = 20;
    
    // 值捕获
    auto captureByValue = [x, y]() {
        // x, y是副本,不能修改
        return x + y;
    };
    cout << "\n值捕获: " << captureByValue() << endl;
    
    // 引用捕获
    auto captureByRef = [&x, &y]() {
        x++;  // 可以修改原变量
        y++;
        return x + y;
    };
    cout << "引用捕获: " << captureByRef() << endl;
    cout << "x = " << x << ", y = " << y << endl;
    
    // 混合捕获
    auto mixedCapture = [x, &y]() {
        // x是值捕获,y是引用捕获
        return x + y;
    };
    
    // 全部值捕获
    auto captureAllByValue = [=]() {
        return x + y;
    };
    
    // 全部引用捕获
    auto captureAllByRef = [&]() {
        x++;
        y++;
    };
    
    // 全部值捕获,但y引用捕获
    auto captureMostByValue = [=, &y]() {
        y = x + y;
    };
    
    // 全部引用捕获,但x值捕获
    auto captureMostByRef = [&, x]() {
        y = x + y;
    };
    
    
    // ============ 可变Lambda ============
    
    int counter = 0;
    
    // 默认值捕获的变量不能修改
    // auto badCounter = [counter]() { counter++; };  // 错误
    
    // 使用mutable允许修改值捕获的变量
    auto goodCounter = [counter]() mutable {
        counter++;  // 修改的是副本
        return counter;
    };
    
    cout << "\n可变Lambda: " << goodCounter() << endl;
    cout << "可变Lambda: " << goodCounter() << endl;
    cout << "原变量: " << counter << endl;  // 原变量不变
    
    
    // ============ 在算法中使用Lambda ============
    
    vector<int> numbers = {5, 2, 8, 1, 9, 3, 7, 4, 6};
    
    // 使用lambda作为谓词
    // 统计偶数个数
    int evenCount = count_if(numbers.begin(), numbers.end(), 
        [](int n) { return n % 2 == 0; });
    cout << "\n偶数个数: " << evenCount << endl;
    
    // 使用lambda排序
    sort(numbers.begin(), numbers.end(), 
        [](int a, int b) { return a > b; });  // 降序
    cout << "降序排序: ";
    for (int n : numbers) {
        cout << n << " ";
    }
    cout << endl;
    
    // 使用lambda遍历
    cout << "遍历: ";
    for_each(numbers.begin(), numbers.end(), 
        [](int n) { cout << n << " "; });
    cout << endl;
    
    
    // ============ 存储Lambda ============
    
    // 使用auto存储
    auto lambda1 = [](int x) { return x * 2; };
    
    // 使用function存储
    function<int(int)> lambda2 = [](int x) { return x * 3; };
    
    // 使用函数指针存储(无捕获的lambda)
    int (*lambda3)(int) = [](int x) { return x * 4; };
    
    cout << "\nlambda1(5) = " << lambda1(5) << endl;
    cout << "lambda2(5) = " << lambda2(5) << endl;
    cout << "lambda3(5) = " << lambda3(5) << endl;
    
    return 0;
}

函数指针

cpp
#include <iostream>
#include <functional>
using namespace std;

// 普通函数
int add(int a, int b) {
    return a + b;
}

int subtract(int a, int b) {
    return a - b;
}

int multiply(int a, int b) {
    return a * b;
}

// 使用函数指针作为参数
int calculate(int a, int b, int (*operation)(int, int)) {
    return operation(a, b);
}

// 使用std::function(更灵活)
int calculate2(int a, int b, function<int(int, int)> operation) {
    return operation(a, b);
}

int main() {
    // ============ 函数指针基础 ============
    
    // 声明函数指针
    int (*funcPtr)(int, int);
    
    // 指向函数
    funcPtr = add;
    
    // 通过函数指针调用
    int result = funcPtr(10, 5);
    cout << "add(10, 5) = " << result << endl;
    
    // 另一种调用方式
    result = (*funcPtr)(10, 5);
    cout << "(*funcPtr)(10, 5) = " << result << endl;
    
    // 指向不同的函数
    funcPtr = subtract;
    cout << "subtract(10, 5) = " << funcPtr(10, 5) << endl;
    
    funcPtr = multiply;
    cout << "multiply(10, 5) = " << funcPtr(10, 5) << endl;
    
    
    // ============ 函数指针数组 ============
    
    int (*operations[])(int, int) = {add, subtract, multiply};
    string names[] = {"加法", "减法", "乘法"};
    
    cout << "\n===== 函数指针数组 =====" << endl;
    for (int i = 0; i < 3; i++) {
        cout << names[i] << ": " << operations[i](10, 5) << endl;
    }
    
    
    // ============ 函数指针作为参数 ============
    
    cout << "\n===== 函数指针作为参数 =====" << endl;
    cout << "calculate(10, 5, add) = " << calculate(10, 5, add) << endl;
    cout << "calculate(10, 5, subtract) = " << calculate(10, 5, subtract) << endl;
    cout << "calculate(10, 5, multiply) = " << calculate(10, 5, multiply) << endl;
    
    
    // ============ 使用std::function ============
    
    // std::function可以存储函数指针、lambda、函数对象
    function<int(int, int)> func;
    
    // 存储普通函数
    func = add;
    cout << "\nstd::function存储函数: " << func(10, 5) << endl;
    
    // 存储lambda
    func = [](int a, int b) { return a / b; };
    cout << "std::function存储lambda: " << func(10, 5) << endl;
    
    // 使用std::function作为参数
    cout << "calculate2(10, 5, lambda) = " << calculate2(10, 5, [](int a, int b) { return a % b; }) << endl;
    
    
    // ============ 回调函数 ============
    
    // 定义回调函数类型
    typedef void (*Callback)(int);
    
    // 执行操作并调用回调
    auto processWithCallback = [](int value, Callback callback) {
        cout << "\n处理值: " << value << endl;
        callback(value);
    };
    
    // 定义回调函数
    auto printValue = [](int value) {
        cout << "回调: 值是 " << value << endl;
    };
    
    auto printDouble = [](int value) {
        cout << "回调: 值的两倍是 " << value * 2 << endl;
    };
    
    processWithCallback(10, printValue);
    processWithCallback(10, printDouble);
    
    return 0;
}

可变参数函数

cpp
#include <iostream>
#include <cstdarg>  // 可变参数头文件
using namespace std;

// ============ C风格可变参数 ============

// 计算多个整数的和
int sum(int count, ...) {
    va_list args;  // 可变参数列表
    va_start(args, count);  // 初始化,count是最后一个固定参数
    
    int total = 0;
    for (int i = 0; i < count; i++) {
        total += va_arg(args, int);  // 获取下一个参数
    }
    
    va_end(args);  // 清理
    return total;
}

// 打印多个字符串
void printStrings(int count, ...) {
    va_list args;
    va_start(args, count);
    
    for (int i = 0; i < count; i++) {
        const char* str = va_arg(args, const char*);
        cout << str << " ";
    }
    
    va_end(args);
    cout << endl;
}

// ============ C++11可变参数模板 ============

// 递归终止条件
void print() {
    cout << endl;
}

// 可变参数模板函数
template<typename T, typename... Args>
void print(T first, Args... rest) {
    cout << first << " ";
    print(rest...);  // 递归调用
}

// 计算多个数的和
template<typename T>
T sumTemplate(T value) {
    return value;
}

template<typename T, typename... Args>
T sumTemplate(T first, Args... rest) {
    return first + sumTemplate(rest...);
}

// 使用折叠表达式(C++17)
// template<typename... Args>
// auto sumFold(Args... args) {
//     return (args + ...);  // 一元右折叠
// }

int main() {
    // C风格可变参数
    cout << "===== C风格可变参数 =====" << endl;
    cout << "sum(3, 1, 2, 3) = " << sum(3, 1, 2, 3) << endl;
    cout << "sum(5, 1, 2, 3, 4, 5) = " << sum(5, 1, 2, 3, 4, 5) << endl;
    
    printStrings(3, "Hello", "World", "C++");
    
    // C++11可变参数模板
    cout << "\n===== C++11可变参数模板 =====" << endl;
    print(1, 2, 3, 4, 5);
    print("Hello", "World", 123, 45.67);
    
    cout << "sumTemplate(1, 2, 3) = " << sumTemplate(1, 2, 3) << endl;
    cout << "sumTemplate(1.1, 2.2, 3.3) = " << sumTemplate(1.1, 2.2, 3.3) << endl;
    
    // C++17折叠表达式
    // cout << "sumFold(1, 2, 3, 4, 5) = " << sumFold(1, 2, 3, 4, 5) << endl;
    
    return 0;
}

本章小结

本章学习了:

  • 函数定义:返回类型、函数名、参数列表、函数体
  • 参数传递:值传递、引用传递、指针传递、常量引用
  • 默认参数:从右向左提供默认值
  • 函数重载:同名函数,参数不同
  • 内联函数:inline关键字,避免函数调用开销
  • 递归函数:函数调用自身,需要终止条件
  • Lambda表达式:匿名函数,捕获列表,mutable
  • 函数指针:指向函数的指针,回调函数
  • 可变参数:va_list、可变参数模板

下一章,我们将学习数组,了解C++数组的定义和使用。