C++ 函数(保姆级教程)
💡一则或许对你有用的小广告
欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论
- 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于
Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...
,点击查看项目介绍 ;演示链接: http://116.62.199.48:7070 ;- 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;
截止目前, 星球 内专栏累计输出 90w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 3100+ 小伙伴加入学习 ,欢迎点击围观
在编程的世界中,函数如同乐高积木一般,是构建复杂程序的基础模块。对于初学者和中级开发者而言,掌握 C++ 函数 的设计与使用,不仅能提升代码的复用性,还能让逻辑结构更加清晰。本文将从函数的定义、参数传递、作用域到高级特性,逐步展开讲解,并通过实例帮助读者理解如何高效地运用这一核心工具。
一、函数的基本概念:程序的“积木块”
1.1 函数的定义与调用
函数是执行特定任务的代码块,通过 定义 和 调用 两个步骤完成功能封装。例如,计算两个数之和的函数可以这样定义:
// 函数定义:返回类型、函数名、参数列表、函数体
int add(int a, int b) {
return a + b;
}
在需要时调用该函数:
int result = add(3, 5); // 调用 add 函数,参数为 3 和 5
比喻:函数就像厨房里的“料理机”,你只需将食材(参数)放入,按下开关(调用函数),就能得到成品(返回结果)。
1.2 函数的组成部分
- 返回类型:函数执行后返回的数据类型(如
int
,double
),若无返回值则用void
。 - 函数名:需遵循标识符命名规则,建议使用有意义的名称(如
calculate_area
)。 - 参数列表:输入数据的容器,可为空(如
void
)。 - 函数体:具体操作的代码块,用花括号
{}
包裹。
示例代码:
// 无返回值的函数示例
void print_message() {
std::cout << "Hello, C++ Functions!";
}
二、参数传递:函数间的“对话方式”
函数通过参数与外部交互,参数传递的方式决定了数据如何在函数内外流动。
2.1 值传递(Pass by Value)
默认的传递方式:函数接收参数的副本,修改副本不会影响原变量。
void modify(int x) {
x = 10; // 仅修改副本
}
int main() {
int num = 5;
modify(num);
std::cout << num; // 输出仍为 5
return 0;
}
2.2 引用传递(Pass by Reference)
通过 &
符号传递变量的地址,函数直接操作原变量。
void modify(int &x) { // 使用引用传递
x = 10; // 修改原变量
}
int main() {
int num = 5;
modify(num);
std::cout << num; // 输出 10
return 0;
}
比喻:值传递像传递物品的复制品,而引用传递则像直接传递钥匙,让对方能操作原物。
2.3 指针传递
通过指针间接修改变量,需手动解引用操作。
void modify(int *x) {
*x = 10; // 通过指针修改原值
}
int main() {
int num = 5;
modify(&num); // 传递地址
std::cout << num; // 输出 10
return 0;
}
三、作用域与生命周期:函数的“可见范围”
3.1 局部变量与全局变量
- 局部变量:定义在函数内部,仅在函数执行期间存在。
- 全局变量:定义在所有函数之外,程序全程可用,但需谨慎使用以避免副作用。
示例代码:
int global_var = 100; // 全局变量
void func() {
int local_var = 200; // 局部变量
std::cout << global_var << " " << local_var; // 输出 100 200
}
3.2 函数嵌套的作用域
C++ 允许函数嵌套定义,但内部函数仅在外部函数内部可见。
void outer() {
void inner() {
// 内部函数,只能在 outer 内调用
}
inner(); // 合法
}
四、函数重载:让函数名“一词多义”
通过参数类型或数量的不同,可为同一函数名赋予多种行为,称为函数重载。
示例代码:
// 重载 add 函数:整数相加
int add(int a, int b) { return a + b; }
// 重载 add 函数:字符串拼接
std::string add(const std::string &s1, const std::string &s2) {
return s1 + s2;
}
int main() {
std::cout << add(3, 5) << " " << add("Hello", " World"); // 输出 8 Hello World
return 0;
}
五、递归函数:自我调用的艺术
递归是函数直接或间接调用自身的行为,常用于解决分治问题(如阶乘、斐波那契数列)。
5.1 递归三要素
- 基准条件(Base Case):终止递归的条件。
- 递归步骤(Recursive Step):缩小问题规模后调用自身。
- 调用逻辑:确保每次递归向基准条件靠近。
示例:计算阶乘
int factorial(int n) {
if (n == 0) return 1; // 基准条件
return n * factorial(n - 1); // 递归步骤
}
比喻:递归如同俄罗斯套娃,每个大娃娃里都有更小的娃娃,直到最小的娃娃无法再分。
六、Lambda 表达式:匿名函数的“轻量级”实现
C++11 引入的 Lambda 表达式,允许在代码块内定义无名函数,常用于算法或回调场景。
语法格式:
[捕获列表](参数列表) -> 返回类型 { 函数体 }
示例代码:
int main() {
auto add = [](int a, int b) { return a + b; }; // 定义 Lambda
std::cout << add(2, 3); // 输出 5
return 0;
}
七、实际案例:计算器程序
结合上述知识点,构建一个简易计算器:
#include <iostream>
// 函数声明
double add(double a, double b);
double subtract(double a, double b);
double multiply(double a, double b);
double divide(double a, double b);
int main() {
double num1, num2;
char op;
std::cout << "Enter operation (e.g., 5 + 3): ";
std::cin >> num1 >> op >> num2;
switch(op) {
case '+': std::cout << add(num1, num2); break;
case '-': std::cout << subtract(num1, num2); break;
case '*': std::cout << multiply(num1, num2); break;
case '/': std::cout << divide(num1, num2); break;
default: std::cout << "Invalid operator";
}
return 0;
}
// 函数定义
double add(double a, double b) { return a + b; }
double subtract(double a, double b) { return a - b; }
double multiply(double a, double b) { return a * b; }
double divide(double a, double b) { return b != 0 ? a / b : 0; }
八、结论
通过本文的学习,读者应能理解 C++ 函数 的核心概念与高级用法,包括参数传递、作用域、重载、递归及 Lambda 表达式。掌握这些内容不仅能提升代码的可维护性,还能为后续学习模板、STL 等高级主题打下基础。建议读者通过实践项目(如计算器、排序算法)深化理解,并逐步探索函数指针、异常处理等进阶技巧。编程之路永无止境,愿函数成为你构建复杂程序的得力工具!