6C++ Primer(第5版)

函数

代码复用与抽象

函数定义参数传递重载内联

🎯 AI 时代的学习建议:不要只读理论。理解这一章的设计动机(为什么需要这个概念?)和边界条件(什么情况下会失效?)。当 AI 生成的代码涉及这些概念时,你能判断它是否用对了场景。AI 能帮你总结内容,但无法替代你亲手阅读、思考、建立直觉的过程。

第6章:函数(Functions)

一、导读

1.1 本章学习目标

第6章深入讲解C++的函数机制。本章核心目标:

  • 掌握函数定义和声明:参数传递方式、返回值
  • 理解函数重载:同名函数不同参数
  • 掌握默认参数和内联函数:性能和便利性的权衡
  • 学会使用lambda表达式:C++11的匿名函数
  • 理解函数指针:回调函数的实现

1.2 为什么本章如此重要

函数是代码复用的基本单位。C++的函数比C更加强大和灵活,支持重载、默认参数、lambda等高级特性。理解这些特性,才能写出高效、可维护的C++代码。

1.3 核心问题引导

值传递、引用传递、const引用传递各有什么优缺点?

函数重载的解析规则是什么?什么情况下会二义性?

lambda表达式的捕获列表有哪些方式?

内联函数真的能提升性能吗?有什么限制?


二、核心概念详解

6.1 函数基础

cpp
#include <iostream>
#include <string>

// 函数声明(原型)
int add(int a, int b);

// 函数定义
int add(int a, int b) {
    return a + b;
}

// 引用传递
void swap(int &a, int &b) {
    int temp = a;
    a = b;
    b = temp;
}

// const引用传递(推荐用于大对象)
void print(const std::string &s) {
    std::cout << s << std::endl;
}

// 默认参数
void greet(const std::string &name, const std::string &greeting = "Hello") {
    std::cout << greeting << ", " << name << "!" << std::endl;
}

int main() {
    std::cout << add(3, 5) << std::endl;  // 8
    
    int x = 10, y = 20;
    swap(x, y);
    std::cout << "x=" << x << ", y=" << y << std::endl;
    
    print("Hello, World!");
    
    greet("Alice");
    greet("Bob", "Hi");
    
    return 0;
}

6.2 函数重载

cpp
#include <iostream>
#include <string>

// 同名函数,不同参数
int add(int a, int b) { return a + b; }
double add(double a, double b) { return a + b; }
std::string add(const std::string &a, const std::string &b) { return a + b; }

// 重载解析规则
void print(int i) { std::cout << "int: " << i << std::endl; }
void print(double d) { std::cout << "double: " << d << std::endl; }
void print(const std::string &s) { std::cout << "string: " << s << std::endl; }

int main() {
    std::cout << add(1, 2) << std::endl;        // 调用int版本
    std::cout << add(1.5, 2.5) << std::endl;    // 调用double版本
    std::cout << add("Hello, ", "World!") << std::endl;  // 调用string版本
    
    print(42);           // int
    print(3.14);         // double
    print("hello");      // string
    
    return 0;
}

6.3 内联函数和constexpr

cpp
// 内联函数:建议编译器内联展开
inline int square(int x) {
    return x * x;
}

// constexpr函数:可以在编译时求值
constexpr int factorial(int n) {
    return (n <= 1) ? 1 : n * factorial(n - 1);
}

int main() {
    // 编译时计算
    constexpr int result = factorial(5);  // 120
    static_assert(result == 120, "factorial(5) should be 120");
    
    // 运行时也可以使用
    int n = 6;
    int runtime_result = factorial(n);
    
    return 0;
}

6.4 Lambda表达式

cpp
#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    // 基本lambda
    auto square = [](int x) { return x * x; };
    std::cout << square(5) << std::endl;  // 25
    
    // 捕获列表
    int factor = 10;
    auto multiply = [factor](int x) { return x * factor; };
    std::cout << multiply(5) << std::endl;  // 50
    
    // 值捕获和引用捕获
    int count = 0;
    auto increment = [&count]() { count++; };
    increment();
    increment();
    std::cout << count << std::endl;  // 2
    
    // 与STL算法配合
    std::vector<int> nums = {5, 2, 8, 1, 9, 3};
    
    // 自定义排序
    std::sort(nums.begin(), nums.end(), [](int a, int b) {
        return a > b;  // 降序
    });
    
    for (int n : nums) {
        std::cout << n << " ";
    }
    std::cout << std::endl;
    
    // find_if
    auto it = std::find_if(nums.begin(), nums.end(), [](int x) {
        return x > 5;
    });
    if (it != nums.end()) {
        std::cout << "First > 5: " << *it << std::endl;
    }
    
    // 泛型lambda(C++14)
    auto print = [](const auto &x) { std::cout << x << std::endl; };
    print(42);
    print(3.14);
    print("hello");
    
    return 0;
}

6.5 函数指针和回调

cpp
#include <iostream>
#include <vector>
#include <algorithm>

// 函数指针
int add(int a, int b) { return a + b; }
int multiply(int a, int b) { return a * b; }

int apply(int a, int b, int (*func)(int, int)) {
    return func(a, b);
}

// 使用typedef简化
typedef int (*BinaryOp)(int, int);

void calculate(int a, int b, BinaryOp op) {
    std::cout << "Result: " << op(a, b) << std::endl;
}

int main() {
    // 函数指针
    BinaryOp op = add;
    std::cout << apply(3, 5, op) << std::endl;  // 8
    
    calculate(3, 5, add);       // 8
    calculate(3, 5, multiply);  // 15
    
    // lambda也可以作为函数指针
    calculate(3, 5, [](int a, int b) { return a - b; });  // -2
    
    return 0;
}

三、实战案例

3.1 函数对象和STL

cpp
#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>

struct Student {
    std::string name;
    int score;
};

int main() {
    std::vector<Student> students = {
        {"Alice", 90}, {"Bob", 85}, {"Charlie", 92},
        {"David", 78}, {"Eve", 88}
    };
    
    // 按分数排序
    std::sort(students.begin(), students.end(), 
              [](const Student &a, const Student &b) {
                  return a.score > b.score;
              });
    
    for (const auto &s : students) {
        std::cout << s.name << ": " << s.score << std::endl;
    }
    
    // 统计
    int total = std::accumulate(students.begin(), students.end(), 0,
                                [](int sum, const Student &s) {
                                    return sum + s.score;
                                });
    std::cout << "Average: " << total / students.size() << std::endl;
    
    // 查找
    auto top = std::max_element(students.begin(), students.end(),
                                [](const Student &a, const Student &b) {
                                    return a.score < b.score;
                                });
    std::cout << "Top student: " << top->name << std::endl;
    
    return 0;
}

四、本章小结

第6章讲解了C++的函数机制:参数传递(值/引用/const引用)、函数重载、默认参数、内联函数、constexpr函数、lambda表达式、函数指针。lambda是C++11最重要的特性之一,与STL算法配合非常强大。


五、思考与练习

思考题

为什么大对象参数推荐用const引用传递?

lambda的捕获列表[=]和[&]有什么区别?

内联函数一定能提升性能吗?

函数重载时,编译器如何选择合适的版本?

编程练习

实现一个通用的排序函数,支持自定义比较器。

使用lambda实现一个简单的计算器。

实现一个高阶函数map,对vector中每个元素应用给定函数。


6/12函数
0%