Appearance
函数
函数是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++数组的定义和使用。
