C++函数参数 #
一、参数传递概述 #
C++支持多种参数传递方式:
- 值传递
- 指针传递
- 引用传递
二、值传递 #
2.1 基本概念 #
值传递会创建参数的副本,函数内修改不影响原值。
cpp
void increment(int x) {
x++; // 修改的是副本
}
int main() {
int a = 10;
increment(a);
std::cout << a << std::endl; // 10,未改变
return 0;
}
2.2 适用场景 #
cpp
// 适合小型数据类型
void process(int x, double y, char c);
// 不适合大型对象
void processBigObject(BigObject obj); // 复制开销大
2.3 优点与缺点 #
cpp
// 优点:安全,不会意外修改原值
void safeFunction(int x) {
x = 100; // 只修改副本
}
// 缺点:复制开销
void inefficient(const std::string str) { // 复制整个字符串
std::cout << str << std::endl;
}
三、指针传递 #
3.1 基本概念 #
指针传递传递的是地址,可以修改原值。
cpp
void increment(int* x) {
(*x)++; // 修改原值
}
int main() {
int a = 10;
increment(&a);
std::cout << a << std::endl; // 11
return 0;
}
3.2 空指针检查 #
cpp
void process(int* ptr) {
if (ptr == nullptr) {
return; // 安全检查
}
*ptr = 100;
}
3.3 交换两个值 #
cpp
void swap(int* a, int* b) {
int temp = *a;
*a = *b;
*b = temp;
}
int main() {
int x = 10, y = 20;
swap(&x, &y);
std::cout << x << ", " << y << std::endl; // 20, 10
return 0;
}
3.4 数组传递 #
cpp
// 数组作为参数时退化为指针
void printArray(int arr[], int size) {
for (int i = 0; i < size; i++) {
std::cout << arr[i] << " ";
}
}
// 等价于
void printArray(int* arr, int size) {
for (int i = 0; i < size; i++) {
std::cout << arr[i] << " ";
}
}
四、引用传递 #
4.1 基本概念 #
引用传递是原值的别名,修改会影响原值。
cpp
void increment(int& x) {
x++; // 修改原值
}
int main() {
int a = 10;
increment(a);
std::cout << a << std::endl; // 11
return 0;
}
4.2 交换两个值 #
cpp
void swap(int& a, int& b) {
int temp = a;
a = b;
b = temp;
}
int main() {
int x = 10, y = 20;
swap(x, y);
std::cout << x << ", " << y << std::endl; // 20, 10
return 0;
}
4.3 常量引用 #
cpp
// 使用const引用避免复制,同时禁止修改
void printString(const std::string& str) {
std::cout << str << std::endl;
// str = "new"; // 错误:不能修改
}
int main() {
std::string s = "Hello";
printString(s);
printString("World"); // 可以接受临时对象
return 0;
}
4.4 引用传递的优点 #
cpp
// 1. 避免复制开销
void processBigObject(const BigObject& obj);
// 2. 语法简洁
void swap(int& a, int& b); // 比 swap(int* a, int* b) 更简洁
// 3. 不能为空
void func(int& ref); // ref一定有效
五、const参数 #
5.1 const值参数 #
cpp
// const值参数:函数内不能修改
void func(const int x) {
// x = 10; // 错误
std::cout << x << std::endl;
}
// 注意:const值参数对调用者无意义,只影响函数内部
5.2 const指针参数 #
cpp
// 指向常量的指针
void func(const int* ptr) {
// *ptr = 10; // 错误:不能修改指向的值
ptr = nullptr; // 可以修改指针本身
}
// 常量指针
void func(int* const ptr) {
*ptr = 10; // 可以修改指向的值
// ptr = nullptr; // 错误:不能修改指针
}
// 指向常量的常量指针
void func(const int* const ptr) {
// 都不能修改
}
5.3 const引用参数 #
cpp
// 最常用的只读参数形式
void printVector(const std::vector<int>& vec) {
for (const auto& x : vec) {
std::cout << x << " ";
}
}
六、默认参数 #
6.1 基本语法 #
cpp
void printMessage(std::string message, int times = 1) {
for (int i = 0; i < times; i++) {
std::cout << message << std::endl;
}
}
int main() {
printMessage("Hello"); // 使用默认值1
printMessage("World", 3); // 指定times为3
return 0;
}
6.2 默认参数规则 #
cpp
// 默认参数必须从右向左连续
void func(int a, int b = 2, int c = 3); // 正确
// void func(int a = 1, int b, int c = 3); // 错误
// 声明和定义分离时,默认参数在声明中
void func(int a, int b = 10); // 声明
void func(int a, int b) { // 定义(不要重复默认参数)
std::cout << a << ", " << b << std::endl;
}
6.3 多个默认参数 #
cpp
void createWindow(std::string title,
int width = 800,
int height = 600,
bool fullscreen = false);
int main() {
createWindow("My Window"); // 全部使用默认值
createWindow("My Window", 1024); // 指定width
createWindow("My Window", 1024, 768); // 指定width和height
createWindow("My Window", 1024, 768, true); // 全部指定
return 0;
}
6.4 默认参数与重载 #
cpp
// 可能产生歧义
void func(int a);
void func(int a, int b = 10);
int main() {
func(5); // 错误:调用哪个?
return 0;
}
七、可变参数 #
7.1 C风格可变参数 #
cpp
#include <cstdarg>
int sum(int count, ...) {
int total = 0;
va_list args;
va_start(args, count);
for (int i = 0; i < count; i++) {
total += va_arg(args, int);
}
va_end(args);
return total;
}
int main() {
std::cout << sum(3, 1, 2, 3) << std::endl; // 6
std::cout << sum(5, 1, 2, 3, 4, 5) << std::endl; // 15
return 0;
}
7.2 初始化列表(C++11) #
cpp
#include <initializer_list>
int sum(std::initializer_list<int> nums) {
int total = 0;
for (int x : nums) {
total += x;
}
return total;
}
int main() {
std::cout << sum({1, 2, 3}) << std::endl; // 6
std::cout << sum({1, 2, 3, 4, 5}) << std::endl; // 15
return 0;
}
7.3 可变参数模板(C++11) #
cpp
template<typename... Args>
void print(Args... args) {
(std::cout << ... << args) << std::endl; // C++17折叠表达式
}
int main() {
print(1, 2, 3); // 123
print("Hello", " ", "World"); // Hello World
return 0;
}
八、参数传递选择 #
8.1 选择指南 #
| 参数类型 | 传递方式 | 示例 |
|---|---|---|
| 小型基本类型 | 值传递 | int, char, double |
| 大型对象 | const引用 | const std::string& |
| 需要修改 | 引用或指针 | int& 或 int* |
| 可选参数 | 指针(可为nullptr) | int* ptr = nullptr |
8.2 示例 #
cpp
// 小型类型:值传递
int add(int a, int b);
// 大型对象:const引用
void process(const std::string& str);
void process(const std::vector<int>& vec);
// 需要修改:引用
void modify(std::string& str);
void fill(std::vector<int>& vec);
// 可选参数:指针
void process(int* ptr = nullptr) {
if (ptr) {
// 处理ptr
} else {
// ptr为空的处理
}
}
九、最佳实践 #
9.1 使用const引用传递大对象 #
cpp
// 不推荐
void process(std::string str); // 复制开销
// 推荐
void process(const std::string& str); // 无复制
9.2 避免使用非const指针参数 #
cpp
// 不推荐:调用者不知道值会被修改
void func(int* x);
// 推荐:使用引用
void func(int& x);
// 或者使用输出参数命名
void getValue(int* outValue);
9.3 合理使用默认参数 #
cpp
// 好的默认参数
void openFile(const std::string& path,
std::ios::openmode mode = std::ios::in);
// 不好的默认参数(容易出错)
void process(int* ptr = nullptr); // 调用者可能忘记检查
十、总结 #
参数传递方式 #
| 方式 | 语法 | 特点 |
|---|---|---|
| 值传递 | T |
复制,安全 |
| 指针传递 | T* |
可为空,可修改 |
| 引用传递 | T& |
不能为空,可修改 |
| const引用 | const T& |
只读,高效 |
最佳实践 #
- 小类型用值传递
- 大对象用const引用
- 需要修改用引用
- 可选参数用指针
- 合理使用默认参数
下一步,让我们学习函数重载!
最后更新:2026-03-26