物理 从0开始手把手教你C++ 2
原帖字数到了,再开一个
声明:由
提供知识点讲解
以下是对 C++ 函数的详细讲解,涵盖定义、声明、参数传递、返回值以及现代 C++ 的特性。
### 1. 函数的基本结构
一个标准的 C++ 函数通常包含以下四个部分:
1. **返回类型**:函数执行完毕后返回给调用者的数据类型。如果不需要返回值,使用 `void`。
2. **函数名**:遵循标识符命名规则,应具有描述性。
3. **参数列表**:传递给函数的输入数据,放在圆括号内。如果没有参数,可以留空或写 `void`。
4. **函数体**:包含具体逻辑的代码块,用花括号 `{}` 包裹。
**语法格式:**
```cpp
返回类型 函数名(参数列表) {
// 函数体
return 返回值; // 如果返回类型不是 void
}
```
**示例:**
```cpp
#include <iostream>
// 定义一个计算两个整数之和的函数
int add(int a, int b) {
return a + b;
}
int main() {
int result = add(3, 5); // 调用函数
std::cout << "结果: " << result << std::endl;
return 0;
}
```
### 2. 函数声明与定义
在 C++ 中,函数可以在使用之前先进行**声明**(Declaration),而在后面进行**定义**(Definition)。这允许我们在 `main` 函数或其他函数中调用尚未完全定义的函数。
* **声明**:只告诉编译器函数的存在、返回类型和参数类型,不包含函数体。通常以分号结尾。
* **定义**:包含完整的函数实现。
**示例:**
```cpp
#include <iostream>
// 函数声明(原型)
int multiply(int x, int y);
int main() {
// 可以在定义之前调用,因为已经声明了
std::cout << multiply(4, 5) << std::endl;
return 0;
}
// 函数定义
int multiply(int x, int y) {
return x * y;
}
```
### 3. 参数传递方式
C++ 支持多种参数传递方式,理解它们的区别对于性能优化和正确性至关重要。
#### 3.1 值传递 (Pass by Value)
默认情况下,C++ 使用值传递。函数接收的是实参的**副本**。修改形参不会影响实参。
```cpp
void changeValue(int n) {
n = 100; // 只修改了副本,不影响外部变量
}
```
#### 3.2 引用传递 (Pass by Reference)
使用 `&` 符号。函数接收的是实参的**别名**。修改形参会直接改变实参。这种方式避免了复制大型对象,提高效率。
```cpp
void changeValueRef(int& n) {
n = 100; // 直接修改了外部变量
}
```
#### 3.3 指针传递 (Pass by Pointer)
使用 `*` 符号。传递变量的内存地址。功能类似引用,但语法更底层,且指针可能为空。
```cpp
void changeValuePtr(int* n) {
if (n != nullptr) {
*n = 100; // 解引用并修改
}
}
```
#### 3.4 常量引用 (Const Reference)
使用 `const &`。既避免了复制开销,又保证了函数内部不会修改实参。这是传递大型对象(如 `std::string`, `std::vector`)时的最佳实践。
```cpp
void printString(const std::string& str) {
// str.length(); // 合法
// str[0] = 'a'; // 非法,编译错误
std::cout << str << std::endl;
}
```
### 4. 默认参数
C++ 允许为函数参数指定默认值。如果调用时未提供该参数,则使用默认值。
**注意**:默认参数必须从右向左依次定义。
```cpp
// b 有默认值 10,a 没有默认值
int power(int base, int exponent = 2) {
int result = 1;
for (int i = 0; i < exponent; ++i) {
result *= base;
}
return result;
}
// 调用
power(3); // 等价于 power(3, 2),返回 9
power(3, 3); // 返回 27
```
### 5. 函数重载 (Function Overloading)
C++ 允许在同一作用域内定义多个同名函数,只要它们的**参数列表不同**(参数个数不同或参数类型不同)。返回类型不同不足以构成重载。
```cpp
int add(int a, int b) {
return a + b;
}
double add(double a, double b) {
return a + b;
}
// 调用时编译器根据参数类型自动选择匹配的函数
add(1, 2); // 调用 int 版本
add(1.5, 2.5); // 调用 double 版本
```
### 6. 内联函数 (Inline Function)
对于频繁调用且代码简短的函数,可以使用 `inline` 关键字建议编译器将函数体直接插入到调用处,以减少函数调用的开销(压栈、跳转等)。
```cpp
inline int max(int a, int b) {
return (a > b) ? a : b;
}
```
*注意:现代编译器优化能力很强,即使不加 `inline`,编译器也可能自动内联短函数;反之,加了 `inline` 也不保证一定内联。它主要是一个提示。*
### 7. 递归函数
函数可以直接或间接调用自身。递归必须有**终止条件**,否则会导致栈溢出。
**示例:计算阶乘**
```cpp
int factorial(int n) {
if (n <= 1) return 1; // 终止条件
return n * factorial(n - 1); // 递归调用
}
```
### 8. Lambda 表达式 (C++11 及以上)
Lambda 表达式允许在代码中直接定义匿名函数,常用于算法库(如 `std::sort`, `std::for_each`)的回调。
**语法:** `[捕获列表](参数列表) -> 返回类型 { 函数体 }`
```cpp
#include <algorithm>
#include <vector>
#include <iostream>
int main() {
std::vector<int> vec = {5, 3, 8, 1};
// 使用 Lambda 表达式作为排序规则(降序)
std::sort(vec.begin(), vec.end(), [](int a, int b) {
return a > b;
});
for (int v : vec) {
std::cout << v << " ";
}
return 0;
}
```
### 总结
* **模块化**:函数将复杂问题分解为小任务。
* **复用性**:一次编写,多次调用。
* **参数传递**:小数据用值传递,大数据用引用或常量引用,需修改时用引用。
* **现代特性**:善用默认参数、重载、内联和 Lambda 表达式可以使代码更简洁高效。
掌握函数的正确使用是编写高质量 C++ 代码的基础。
共1条回复
时间正序