C++入门教程:函数与作用域详解
本文摘要
/ 函数定义:返回类型 函数名(参数列表) { 函数体 }// 无返回值函数// 调用无参函数// 调用带参函数,接收返回值return 0;当函数定义在使用之后时,需要先声明//…
本文是 C++ 系列教程的第 3 篇。上一篇讲解了运算符、表达式与控制流程,本篇深入讲解函数:定义与调用、参数传递方式、函数重载、递归、内联函数,以及变量作用域与生命周期。
一、函数基础
1.1 函数的作用
函数是组织代码的基本单元,它把一段完成特定功能衺起来,实现:
- 复用:同一段逻辑只写一次,多处调用。
- 抽象:调用者只需关心「做什么」,不必关心「怎么做」。
- 维护:修改只需改一处。
1.2 函数定义与调用
#include <iostream>using namespace std;
// 函数定义:返回类型 函数名(参数列表) { 函数体 }int add(int a, int b) { return a + b;}
// 无返回值函数void printLine() { cout << "==========" << endl;}
int main() { printLine(); // 调用无参函数 int sum = add(3, 5); // 调用带参函数,接收返回值 cout << "3 + 5 = " << sum << endl; printLine(); return 0;}1.3 函数声明与定义分离
当函数定义在使用之后时,需要先声明:
#include <iostream>using namespace std;
// 函数声明(原型):只写签名,不写函数体int multiply(int a, int b);
int main() { cout << "4 x 7 = " << multiply(4, 7) << endl; return 0;}
// 函数定义放在后面int multiply(int a, int b) { return a * b;}二、参数传递
2.1 值传递(传值)
#include <iostream>using namespace std;
void changeValue(int x) { x = 100; // 修改的是副本}
int main() { int num = 10; changeValue(num); cout << "num = " << num << endl; // 10,原值不变 return 0;}值传递时,参数是实参的拷贝,函数内修改不影响外部变量。
2.2 引用传递(传引用)
#include <iostream>using namespace std;
void swap(int &a, int &b) { // 引用参数,直接操作原变量 int temp = a; a = b; b = temp;}
int main() { int x = 3, y = 7; swap(x, y); cout << "x = " << x << ", y = " << y << endl; // x = 7, y = 3 return 0;}2.3 const 引用
当函数不需要修改参数但又想避免拷贝开销时,用 const 引用:
#include <iostream>#include <string>using namespace std;
// 传入大对象(如字符串)用 const 引用,避免拷贝且保证不修改void printMessage(const string &msg) { cout << "消息: " << msg << endl; // msg = "xxx"; // 错误!const 引用不可修改}
int main() { string s = "Hello C++"; printMessage(s); return 0;}2.4 三种传递方式对比
| 方式 | 语法 | 能否修改原值 | 性能 |
|---|---|---|---|
| 值传递 | int x |
否 | 拷贝开销 |
| 引用传递 | int &x |
是 | 无拷贝 |
| const 引用 | const int &x |
否 | 无拷贝 |
三、默认参数与函数重载
3.1 默认参数
#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;}
int main() { cout << "3^2 = " << power(3) << endl; // 9,exp 用默认值 2 cout << "3^3 = " << power(3, 3) << endl; // 27 return 0;}规则:默认参数必须从右往左连续设置,如 f(int a, int b = 1, int c = 2) 合法,f(int a = 1, int b) 不合法。
3.2 函数重载
同名函数,参数列表不同(类型、个数、顺序),编译器根据实参选择:
#include <iostream>using namespace std;
// 三个同名函数,参数不同int max(int a, int b) { return a > b ? a : b;}
double max(double a, double b) { return a > b ? a : b;}
int max(int a, int b, int c) { return max(max(a, b), c);}
int main() { cout << "max(3, 7) = " << max(3, 7) << endl; // int 版本 cout << "max(3.5, 2.8) = " << max(3.5, 2.8) << endl; // double 版本 cout << "max(1, 5, 3) = " << max(1, 5, 3) << endl; // 三参版本 return 0;}注意:重载仅凭返回类型不同无法区分(int f() 和 double f() 不能共存)。
四、递归
4.1 递归原理
递归是函数调用自身的技巧,必须包含:
- 基线条件:终止递归的判断。
- 递归条件:向基线条件逼近的调用。
#include <iostream>using namespace std;
// 阶乘:n! = n * (n-1)!int factorial(int n) { if (n <= 1) return 1; // 基线条件 return n * factorial(n - 1); // 递归调用}
// 斐波那契:f(n) = f(n-1) + f(n-2)int fibonacci(int n) { if (n <= 1) return n; // 基线条件 return fibonacci(n - 1) + fibonacci(n - 2);}
int main() { cout << "5! = " << factorial(5) << endl; // 120 cout << "斐波那契第10项 = " << fibonacci(10) << endl; // 55 return 0;}4.2 递归执行过程(以 factorial(4) 为例)
factorial(4) = 4 * factorial(3) = 4 * (3 * factorial(2)) = 4 * (3 * (2 * factorial(1))) = 4 * (3 * (2 * 1)) = 244.3 递归 vs 迭代
| 维度 | 递归 | 迭代(循环) |
|---|---|---|
| 代码 | 简洁,符合数学定义 | 略复杂 |
| 性能 | 有函数调用开销,深递归可能栈溢出 | 高效 |
| 适用 | 树、图、分治等天然递归结构 | 简单重复计算 |
五、内联函数
#include <iostream>using namespace std;
// inline 建议编译器将函数体展开到调用处(消除调用开销)inline int square(int x) { return x * x;}
int main() { // 编译后等价于直接写 x*x cout << "7^2 = " << square(7) << endl; // 49 return 0;}适用:函数体很小(几行)、被频繁调用。注意:inline 只是建议,大型函数编译器会忽略。
六、变量作用域与生命周期
6.1 局部变量与全局变量
#include <iostream>using namespace std;
int globalCount = 0; // 全局变量:整个文件可见,生命周期为程序运行期
void increment() { int local = 1; // 局部变量:函数内可见,函数结束即销毁 globalCount += local;}
int main() { increment(); increment(); cout << "globalCount = " << globalCount << endl; // 2
// cout << local; // 错误!local 在 main 中不可见 return 0;}6.2 局部变量的遮蔽
#include <iostream>using namespace std;
int x = 100; // 全局 x
int main() { int x = 5; // 局部 x 遮蔽全局 x cout << "局部 x = " << x << endl; // 5 cout << "全局 x = " << ::x << endl; // 100(用 :: 访问全局) { int x = 50; // 内层块又遮蔽外层局部 cout << "块内 x = " << x << endl; // 50 } cout << "外层局部 x = " << x << endl; // 5 return 0;}6.3 static 局部变量
#include <iostream>using namespace std;
void counter() { static int count = 0; // static 局部:只初始化一次,函数结束后保留值 count++; cout << "第 " << count << " 次调用" << endl;}
int main() { counter(); // 第 1 次调用 counter(); // 第 2 次调用 counter(); // 第 3 次调用 return 0;}七、函数指针(了解)
#include <iostream>using namespace std;
int add(int a, int b) { return a + b; }int subtract(int a, int b) { return a - b; }
int main() { // 函数指针:指向函数的指针 int (*operation)(int, int); operation = add; cout << "add(10, 3) = " << operation(10, 3) << endl; // 13
operation = subtract; cout << "subtract(10, 3) = " << operation(10, 3) << endl; // 7 return 0;}八、实战:简易计算器函数库
综合本篇知识,编写一个可复用的计算器函数库:
#include <iostream>using namespace std;
// 函数库:加减乘除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) { if (b == 0) { cout << "错误:除数不能为 0" << endl; return 0; } return a / b;}
// 函数指针数组:把运算函数装进数组,根据索引调用double (*operations[4])(double, double) = {add, subtract, multiply, divide};const char *names[4] = {"加法", "减法", "乘法", "除法"};
int main() { double a = 20, b = 4; for (int i = 0; i < 4; i++) { cout << names[i] << ": " << a << " 与 " << b << " 的运算结果 = " << operations[i](a, b) << endl; } return 0;}运行示例:
加法: 20 与 4 的运算结果 = 24减法: 20 与 4 的运算结果 = 16乘法: 20 与 4 的运算结果 = 80除法: 20 与 4 的运算结果 = 5总结
本篇讲解了函数的定义与调用、三种参数传递方式(值/引用/const 引用)、默认参数、函数重载、递归、内联函数、变量作用域与生命周期、函数指针,并用计算器函数库串联实战。重点掌握:值传递与引用传递的区别、重载规则、递归的基线条件、static 局部变量。
下一篇将讲解数组、字符串与指针入门,敬请期待!
C++入门教程:函数与作用域详解
作者:Wang Shijie
本文链接:https://wsj-blog.pages.dev/posts/c-ru-men-jiao-cheng-han-shu-yu-zuo-yong-yu-xiang-jie/
本文采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。
留言评论
评论资源加载失败,请重试。