第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中每个元素应用给定函数。