====== 第四章 函数 ====== 本章将详细介绍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); } ===== 下一章 ===== 继续学习:[[第五章_类与对象|第五章 类与对象]]