====== 第四章 函数 ======
本章将详细介绍C++中的函数,包括函数的定义与调用、函数重载、默认参数、内联函数、递归等核心概念。
===== 4.1 函数基础 =====
=== 4.1.1 函数的定义 ===
函数是完成特定任务的独立代码块,由函数头和函数体组成。
// 函数的基本结构
返回类型 函数名(参数列表) {
// 函数体
return 返回值; // 如果返回类型不是void
}
// 具体示例
#include
using namespace std;
// 无参数、无返回值的函数
void sayHello() {
cout << "Hello, World!" << endl;
}
// 有参数、无返回值的函数
void greet(string name) {
cout << "Hello, " << name << "!" << endl;
}
// 有参数、有返回值的函数
int add(int a, int b) {
return a + b;
}
// 多个参数的函数
double calculateArea(double length, double width) {
return length * width;
}
int main() {
sayHello();
greet("Alice");
int sum = add(10, 20);
cout << "Sum: " << sum << endl;
double area = calculateArea(5.5, 3.0);
cout << "Area: " << area << endl;
return 0;
}
=== 4.1.2 函数声明与定义分离 ===
// math_utils.h - 头文件
#ifndef MATH_UTILS_H
#define MATH_UTILS_H
// 函数声明(原型)
int add(int a, int b);
int subtract(int a, int b);
int multiply(int a, int b);
double divide(int a, int b);
#endif
// math_utils.cpp - 实现文件
#include "math_utils.h"
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;
}
double divide(int a, int b) {
if (b == 0) {
// 错误处理
return 0;
}
return static_cast(a) / b;
}
// main.cpp
#include
#include "math_utils.h"
using namespace std;
int main() {
cout << "10 + 5 = " << add(10, 5) << endl;
cout << "10 - 5 = " << subtract(10, 5) << endl;
cout << "10 * 5 = " << multiply(10, 5) << endl;
cout << "10 / 5 = " << divide(10, 5) << endl;
return 0;
}
=== 4.1.3 参数传递方式 ===
#include
using namespace std;
// 1. 值传递(默认)- 创建副本
void swapByValue(int a, int b) {
int temp = a;
a = b;
b = temp;
cout << "Inside swapByValue: a=" << a << ", b=" << b << endl;
}
// 2. 引用传递 - 操作原变量
void swapByReference(int& a, int& b) {
int temp = a;
a = b;
b = temp;
}
// 3. 指针传递 - 通过地址操作
void swapByPointer(int* a, int* b) {
int temp = *a;
*a = *b;
*b = temp;
}
// 4. const引用传递 - 避免拷贝,保护原数据
void printLargeObject(const vector& vec) {
// vec.push_back(1); // 错误!不能修改const引用
for (int x : vec) {
cout << x << " ";
}
cout << endl;
}
int main() {
int x = 10, y = 20;
// 值传递 - 不改变原变量
swapByValue(x, y);
cout << "After swapByValue: x=" << x << ", y=" << y << endl;
// 引用传递 - 改变原变量
swapByReference(x, y);
cout << "After swapByReference: x=" << x << ", y=" << y << endl;
// 指针传递 - 改变原变量
swapByPointer(&x, &y);
cout << "After swapByPointer: x=" << x << ", y=" << y << endl;
// const引用
vector large(1000, 1);
printLargeObject(large);
return 0;
}
===== 4.2 函数重载 =====
=== 4.2.1 重载基础 ===
函数重载允许在同一作用域内定义多个同名函数,只要它们的参数列表不同。
#include
#include
using namespace std;
// 重载函数:同名不同参数
int add(int a, int b) {
cout << "int add" << endl;
return a + b;
}
double add(double a, double b) {
cout << "double add" << endl;
return a + b;
}
int add(int a, int b, int c) {
cout << "three int add" << endl;
return a + b + c;
}
string add(const string& a, const string& b) {
cout << "string add" << endl;
return a + b;
}
int main() {
cout << add(1, 2) << endl; // 调用 int add
cout << add(1.5, 2.5) << endl; // 调用 double add
cout << add(1, 2, 3) << endl; // 调用 three int add
cout << add(string("Hello"), string(" World")) << endl;
return 0;
}
=== 4.2.2 重载解析规则 ===
#include
using namespace std;
void func(int a) {
cout << "func(int)" << endl;
}
void func(double a) {
cout << "func(double)" << endl;
}
void func(int a, int b) {
cout << "func(int, int)" << endl;
}
void func(long a) {
cout << "func(long)" << endl;
}
int main() {
func(10); // 精确匹配 func(int)
func(3.14); // 精确匹配 func(double)
func(10, 20); // 精确匹配 func(int, int)
// func(3.14f); // 可以匹配 func(int) 或 func(double)
// 会选择 func(double),因为float到double是提升
// 歧义调用
// func(10L); // 错误:可以匹配 func(int) 或 func(long)
// 显式转换解决歧义
func(static_cast(10L));
func(static_cast(10L));
return 0;
}
=== 4.2.3 重载的限制 ===
#include
using namespace std;
// 返回类型不能用于区分重载
// int getValue() { return 0; }
// double getValue() { return 0.0; } // 错误:重定义
// 默认参数可能导致歧义
void print(int a, int b = 10) {
cout << "print(int, int)" << endl;
}
void print(int a) {
cout << "print(int)" << endl;
}
int main() {
print(5, 10); // 调用 print(int, int)
// print(5); // 错误:歧义,可以匹配两个函数
return 0;
}
===== 4.3 默认参数 =====
=== 4.3.1 默认参数的使用 ===
#include
#include
using namespace std;
// 默认参数必须从右向左连续
void printInfo(string name, int age = 18, string country = "China") {
cout << "Name: " << name << endl;
cout << "Age: " << age << endl;
cout << "Country: " << country << endl;
cout << endl;
}
// 函数声明中指定默认参数,定义中不再指定
void connect(string host, int port = 8080);
void connect(string host, int port) {
cout << "Connecting to " << host << ":" << port << endl;
}
// 默认参数与重载结合
class Box {
public:
// 构造函数重载
Box() : width(1), height(1), depth(1) {}
Box(double w) : width(w), height(1), depth(1) {}
Box(double w, double h) : width(w), height(h), depth(1) {}
Box(double w, double h, double d) : width(w), height(h), depth(d) {}
// 或者用默认参数(更简洁)
// Box(double w = 1, double h = 1, double d = 1)
// : width(w), height(h), depth(d) {}
private:
double width, height, depth;
};
int main() {
printInfo("Alice"); // 使用所有默认值
printInfo("Bob", 25); // 使用country的默认值
printInfo("Charlie", 30, "USA"); // 不使用默认值
connect("localhost"); // 使用默认端口8080
connect("localhost", 3000); // 指定端口
return 0;
}
=== 4.3.2 默认参数的注意事项 ===
#include
using namespace std;
// 1. 默认参数不能重复指定
void func(int a, int b = 10);
// void func(int a, int b = 10) { } // 定义时不能再指定默认参数
void func(int a, int b) { }
// 2. 默认参数在声明中指定,头文件中可见
// 头文件:void draw(int x, int y, int color = 0xFFFFFF);
// 3. 默认参数可以是表达式
int getDefaultValue() {
return 100;
}
void setValue(int val = getDefaultValue()) {
cout << "Value: " << val << endl;
}
// 4. 默认参数与函数指针
void process(int a, int b = 10);
int main() {
void (*ptr1)(int, int) = process; // 正确
// void (*ptr2)(int) = process; // 错误,类型不匹配
setValue(); // 使用默认值100
setValue(50); // 使用50
return 0;
}
===== 4.4 内联函数 =====
=== 4.4.1 内联函数的概念 ===
内联函数建议编译器将函数调用替换为函数体,减少函数调用的开销。
#include
using namespace std;
// 普通函数
int maxNormal(int a, int b) {
return (a > b) ? a : b;
}
// 内联函数
inline int maxInline(int a, int b) {
return (a > b) ? a : b;
}
// 内联函数与宏的比较
#define MAX_MACRO(a, b) ((a) > (b) ? (a) : (b))
inline int maxInlineSafe(int a, int b) {
return (a > b) ? a : b;
}
int main() {
int x = 5, y = 3;
// 宏的问题
int result1 = MAX_MACRO(x++, y++);
// 展开为: ((x++) > (y++) ? (x++) : (y++))
// x和y可能被增加两次!
// 内联函数安全
int result2 = maxInlineSafe(x++, y++);
// x和y只增加一次
cout << "Macro result: " << result1 << endl;
cout << "Inline result: " << result2 << endl;
// 现代C++:使用constexpr函数(C++11)
constexpr int maxConstexpr(int a, int b) {
return (a > b) ? a : b;
}
constexpr int m = maxConstexpr(10, 20); // 编译时计算
return 0;
}
=== 4.4.2 内联的使用建议 ===
// 适合内联的情况:
// 1. 函数体很小(1-3行)
// 2. 频繁调用的简单函数
// 3. 在头文件中定义
// inline.h
#ifndef INLINE_H
#define INLINE_H
inline int square(int x) {
return x * x;
}
inline double circleArea(double radius) {
const double PI = 3.14159;
return PI * radius * radius;
}
// 类中的内联成员函数
class Point {
public:
// 隐式内联
int getX() const { return x; }
int getY() const { return y; }
// 显式内联
inline void setX(int newX) { x = newX; }
inline void setY(int newY) { y = newY; }
private:
int x, y;
};
#endif
===== 4.5 递归函数 =====
=== 4.5.1 递归基础 ===
递归是函数调用自身的编程技术,需要基准条件和递归步骤。
#include
using namespace std;
// 阶乘:n! = n * (n-1)!
unsigned long long factorial(int n) {
// 基准条件
if (n <= 1) {
return 1;
}
// 递归步骤
return n * factorial(n - 1);
}
// 斐波那契数列
unsigned long long fibonacci(int n) {
if (n <= 1) {
return n;
}
return fibonacci(n - 1) + fibonacci(n - 2);
}
// 改进的斐波那契(使用记忆化)
unsigned long long fibMemo(int n, unsigned long long* memo) {
if (n <= 1) return n;
if (memo[n] != 0) return memo[n];
memo[n] = fibMemo(n - 1, memo) + fibMemo(n - 2, memo);
return memo[n];
}
unsigned long long fibonacciFast(int n) {
unsigned long long* memo = new unsigned long long[n + 1]();
unsigned long long result = fibMemo(n, memo);
delete[] memo;
return result;
}
int main() {
cout << "Factorial:" << endl;
for (int i = 0; i <= 10; i++) {
cout << i << "! = " << factorial(i) << endl;
}
cout << "\nFibonacci:" << endl;
for (int i = 0; i <= 10; i++) {
cout << "F(" << i << ") = " << fibonacciFast(i) << endl;
}
return 0;
}
=== 4.5.2 更多递归示例 ===
#include
using namespace std;
// 幂运算
double power(double base, int exp) {
if (exp == 0) return 1;
if (exp < 0) return 1 / power(base, -exp);
double half = power(base, exp / 2);
if (exp % 2 == 0) {
return half * half;
} else {
return half * half * base;
}
}
// 欧几里得算法(最大公约数)
int gcd(int a, int b) {
if (b == 0) return a;
return gcd(b, a % b);
}
// 汉诺塔
void hanoi(int n, char from, char aux, char to) {
if (n == 1) {
cout << "Move disk 1 from " << from << " to " << to << endl;
return;
}
hanoi(n - 1, from, to, aux);
cout << "Move disk " << n << " from " << from << " to " << to << endl;
hanoi(n - 1, aux, from, to);
}
// 二分查找(递归实现)
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;
if (arr[mid] > target) {
return binarySearch(arr, left, mid - 1, target);
}
return binarySearch(arr, mid + 1, right, target);
}
// 字符串反转
void reverseString(char str[], int left, int right) {
if (left >= right) return;
swap(str[left], str[right]);
reverseString(str, left + 1, right - 1);
}
int main() {
cout << "2^10 = " << power(2, 10) << endl;
cout << "GCD(48, 18) = " << gcd(48, 18) << endl;
cout << "\nHanoi (3 disks):" << endl;
hanoi(3, 'A', 'B', 'C');
int arr[] = {1, 3, 5, 7, 9, 11, 13};
int index = binarySearch(arr, 0, 6, 7);
cout << "\nBinary search: 7 is at index " << index << endl;
char str[] = "Hello";
reverseString(str, 0, 4);
cout << "Reversed: " << str << endl;
return 0;
}
===== 4.6 函数指针与回调 =====
=== 4.6.1 函数指针 ===
#include
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 main() {
// 定义函数指针
int (*operation)(int, int);
// 赋值
operation = add;
cout << "10 + 5 = " << operation(10, 5) << endl;
operation = subtract;
cout << "10 - 5 = " << operation(10, 5) << endl;
operation = multiply;
cout << "10 * 5 = " << operation(10, 5) << endl;
// 函数指针数组
int (*ops[])(int, int) = {add, subtract, multiply};
const char* names[] = {"Add", "Subtract", "Multiply"};
for (int i = 0; i < 3; i++) {
cout << names[i] << ": " << ops[i](8, 3) << endl;
}
// 使用using定义类型别名(C++11)
using Operation = int (*)(int, int);
Operation op = add;
cout << op(20, 10) << endl;
// 使用auto(C++11)
auto autoOp = multiply;
cout << autoOp(5, 6) << endl;
return 0;
}
=== 4.6.2 回调函数 ===
#include
#include
using namespace std;
// 回调函数类型
using CompareFunc = bool (*)(int, int);
// 冒泡排序,接受比较函数
void bubbleSort(vector& arr, CompareFunc compare) {
int n = arr.size();
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n - i - 1; j++) {
if (compare(arr[j], arr[j + 1])) {
swap(arr[j], arr[j + 1]);
}
}
}
}
// 比较函数
bool ascending(int a, int b) { return a > b; }
bool descending(int a, int b) { return a < b; }
// 回调函数的另一个例子:遍历数组
void forEach(const vector& arr, void (*callback)(int)) {
for (int x : arr) {
callback(x);
}
}
void printElement(int x) {
cout << x << " ";
}
void printSquare(int x) {
cout << x * x << " ";
}
int main() {
vector numbers = {64, 34, 25, 12, 22, 11, 90};
cout << "Original: ";
forEach(numbers, printElement);
cout << endl;
// 升序排序
bubbleSort(numbers, ascending);
cout << "Ascending: ";
forEach(numbers, printElement);
cout << endl;
// 降序排序
bubbleSort(numbers, descending);
cout << "Descending: ";
forEach(numbers, printElement);
cout << endl;
// 打印平方
cout << "Squares: ";
forEach(numbers, printSquare);
cout << endl;
return 0;
}
===== 4.7 Lambda表达式(C++11) =====
#include
#include
#include
using namespace std;
int main() {
vector numbers = {1, 2, 3, 4, 5};
// 基本lambda语法:[捕获](参数) -> 返回类型 { 函数体 }
// 1. 最简单的lambda
auto sayHello = []() { cout << "Hello!" << endl; };
sayHello();
// 2. 带参数的lambda
auto add = [](int a, int b) -> int { return a + b; };
cout << "3 + 5 = " << add(3, 5) << endl;
// 3. 捕获外部变量
int x = 10;
int y = 20;
// 值捕获
auto captureByValue = [x, y]() { return x + y; };
x = 100; // 不影响lambda内部的x
cout << "Capture by value: " << captureByValue() << endl; // 30
// 引用捕获
x = 10;
auto captureByRef = [&x, &y]() { return x + y; };
x = 100; // 影响lambda内部的x
cout << "Capture by reference: " << captureByRef() << endl; // 120
// 隐式捕获
auto implicitValue = [=]() { return x + y; }; // 全部值捕获
auto implicitRef = [&]() { return x + y; }; // 全部引用捕获
auto mixed = [=, &x]() { return x + y; }; // y值捕获,x引用捕获
// 4. 在算法中使用lambda
vector nums = {5, 2, 8, 1, 9, 3};
// 排序
sort(nums.begin(), nums.end(), [](int a, int b) {
return a > b; // 降序
});
cout << "Sorted: ";
for (int n : nums) cout << n << " ";
cout << endl;
// 查找第一个大于5的元素
auto it = find_if(nums.begin(), nums.end(), [](int n) {
return n > 5;
});
if (it != nums.end()) {
cout << "First > 5: " << *it << endl;
}
// 5. 泛型lambda(C++14)
auto genericAdd = [](auto a, auto b) { return a + b; };
cout << "Add ints: " << genericAdd(1, 2) << endl;
cout << "Add doubles: " << genericAdd(1.5, 2.5) << endl;
cout << "Concat strings: " << genericAdd(string("Hello"), string(" World")) << endl;
return 0;
}
===== 4.8 本章小结 =====
本章我们学习了:
* 函数的定义、声明和调用
* 三种参数传递方式:值传递、引用传递、指针传递
* 函数重载的规则和限制
* 默认参数的使用和注意事项
* 内联函数的概念和使用建议
* 递归函数的设计和优化
* 函数指针和回调函数
* Lambda表达式(C++11)
===== 练习题 =====
**基础练习:**
1. 编写重载函数abs,分别处理int、double和long
2. 实现一个函数swap,使用指针交换两个double的值
3. 编写递归函数计算字符串长度
4. 使用默认参数实现print函数,可以打印1到3个整数
**进阶练习:**
5. 实现快排算法,使用函数指针/回调实现自定义比较
6. 编写函数实现任意进制的数字转换(2-36进制)
7. 使用递归实现目录遍历(模拟,不需要实际文件操作)
**思考题:**
8. 比较内联函数和宏的优缺点,什么情况下应该选择内联函数?
9. 递归和迭代如何选择?各有什么优缺点?
10. 研究尾递归优化,C++编译器是否支持?
===== 参考答案 =====
**练习1参考:**
int abs(int n) { return n < 0 ? -n : n; }
double abs(double n) { return n < 0 ? -n : n; }
long abs(long n) { return n < 0 ? -n : n; }
**练习3参考:**
size_t strLength(const char* str) {
if (*str == '\0') return 0;
return 1 + strLength(str + 1);
}
**练习5参考:**
void quickSort(int arr[], int left, int right, bool (*compare)(int, int)) {
if (left >= right) return;
int pivot = arr[(left + right) / 2];
int i = left, j = right;
while (i <= j) {
while (compare(arr[i], pivot)) i++;
while (compare(pivot, arr[j])) j--;
if (i <= j) {
swap(arr[i], arr[j]);
i++;
j--;
}
}
quickSort(arr, left, j, compare);
quickSort(arr, i, right, compare);
}
===== 下一章 =====
继续学习:[[第五章_类与对象|第五章 类与对象]]