C++: 函数重载与默认参数

最后更新:2026-08-26

有时候,你需要一个函数能处理不同类型不同数量的参数。

比如 print 函数,既能打印整数,又能打印浮点数,还能打印字符串。

C++ 提供了两个特性来实现这个——函数重载默认参数


1. 函数重载(Function Overloading)

(1) 1.1 什么是函数重载?

函数重载允许你定义多个同名函数,但它们的参数列表不同

函数签名 含义
print(int x) 打印整数
print(double x) 打印浮点数
print(const std::string& x) 打印字符串

调用时,编译器会根据实参的类型自动选择正确的函数。

▶ 示例 1:函数重载(难度⭐)

CPP
#include <iostream>
#include <string>

// 重载函数:打印整数
void print(int x) {
 std::cout << "整数:" << x << std::endl;
}

// 重载函数:打印浮点数
void print(double x) {
 std::cout << "浮点数:" << x << std::endl;
}

// 重载函数:打印字符串
void print(const std::string& x) {
 std::cout << "字符串:" << x << std::endl;
}

int main() {
 print(5); // 调用 print(int)
 print(3.14); // 调用 print(double)
 print("Hello"); // 调用 print(const char*)
 
 return 0;
}
▶ 试一试

输出:

TEXT 📖 仅展示
整数:5
浮点数:3.14
字符串:Hello

⚠️ 重点: 函数重载的条件是参数列表不同(类型不同、数量不同、或顺序不同)。返回类型不同不算重载



2. 函数重载的规则

(1) 2.1 什么算"参数列表不同"?

不同点 示例
类型不同 void foo(int x) vs void foo(double x)
数量不同 void foo(int x) vs void foo(int x, int y)
顺序不同 void foo(int x, double y) vs void foo(double x, int y)

(2) 2.2 什么不算重载?

情况 示例 结果
只有返回类型不同 int foo() vs double foo() ❌ 编译报错:重定义
只有参数名不同 void foo(int x) vs void foo(int y) ❌ 编译报错:重定义


3. 默认参数(Default Arguments)

(1) 3.1 基本用法

默认参数允许你在调用函数时省略某些实参,编译器会自动用默认值。

CPP
#include <iostream>

// 声明时指定默认参数
void print(int x, int y = 10) {
 std::cout << "x = " << x << ", y = " << y << std::endl;
}

int main() {
 print(5); // 只传一个参数,y 用默认值 10
 print(5, 20); // 传两个参数,y 被改成 20
 
 return 0;
}

(2) 3.2 默认参数的规则

  1. 只能从右往左设置默认值
CPP
void foo(int a, int b = 10, int c = 20); // ✅ 正确
void bar(int a = 5, int b, int c); // ❌ 错误:a 有默认值,但 b 没有
  1. 默认参数只能在函数原型或函数定义中指定一次
CPP
int add(int a, int b = 10); // 在函数原型中指定默认值

int main() {
std::cout << add(5) << std::endl;
return 0;
}

int add(int a, int b) { // ✅ 定义中不用再写默认值
return a + b;
}


4. 函数重载 + 默认参数

函数重载和默认参数可以一起用,让函数更灵活。

▶ 示例 2:打印带分隔符的数组(难度⭐⭐)

CPP
#include <iostream>
#include <string>

// 重载 + 默认参数
void printArray(int arr, int length) {
 printArray(arr, length, ", "); // 调用下面那个函数,用默认分隔符
}

void printArray(int arr, int length, const std::string& delimiter) {
 for (int i = 0; i < length; i++) {
 std::cout << arr[i];
 if (i < length - 1) {
 std::cout << delimiter;
 }
 }
 std::cout << std::endl;
}

int main() {
 int arr[5] = {1, 2, 3, 4, 5};
 
 printArray(arr, 5); // 用默认分隔符 ", "
 printArray(arr, 5, " - "); // 用自定义分隔符 " - "
 
 return 0;
}
▶ 试一试

输出:

TEXT 📖 仅展示
1, 2, 3, 4, 5
1 - 2 - 3 - 4 - 5


5. 实战:简单的日志函数

▶ 示例 3:带日志级别的打印函数(难度⭐⭐)

CPP
#include <iostream>
#include <string>
#include <ctime>

// 日志级别
enum LogLevel {
 INFO,
 WARNING,
 ERROR
};

// 获取当前时间字符串
std::string getCurrentTime() {
 std::time_t now = std::time(nullptr);
 std::tm* tm = std::localtime(&now);
 char buffer[80];
 std::strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", tm);
 return std::string(buffer);
}

// 重载函数:打印日志
void log(const std::string& message) {
 log(message, INFO); // 默认日志级别:INFO
}

void log(const std::string& message, LogLevel level) {
 std::string levelStr;
 if (level == INFO) {
 levelStr = "INFO";
 } else if (level == WARNING) {
 levelStr = "WARNING";
 } else {
 levelStr = "ERROR";
 }
 
 std::cout << "[" << getCurrentTime() << "] [" << levelStr << "] " << message << std::endl;
}

int main() {
 log("程序启动"); // 用默认日志级别
 log("内存不足", WARNING);
 log("文件打开失败", ERROR);
 
 return 0;
}
▶ 试一试

输出:

TEXT 📖 仅展示
[] [] 

输出(示例):

TEXT 📖 仅展示
[2026-06-28 22:30:00] [INFO] 程序启动
[2026-06-28 22:30:01] [WARNING] 内存不足
[2026-06-28 22:30:02] [ERROR] 文件打开失败


6. 常见错误

(1) 6.1 函数重载歧义

错误示例:

CPP
#include <iostream>

void foo(int x) {
 std::cout << "foo(int)" << std::endl;
}

void foo(double x) {
 std::cout << "foo(double)" << std::endl;
}

int main() {
 foo(5); // ✅ 调用 foo(int)
 foo(3.14); // ✅ 调用 foo(double)
 foo('A'); // ❌ 歧义:char 可以转换成 int 或 double
 return 0;
}

编译错误信息:

TEXT 📖 仅展示
error: call to 'foo' is ambiguous

修复: 显式类型转换:

CPP
foo(static_castint('A')); // 调用 foo(int)
foo(static_castdouble('A')); // 调用 foo(double)

(2) 6.2 默认参数导致重载歧义

错误示例:

CPP
#include <iostream>

void foo(int x) {
 std::cout << "foo(int)" << std::endl;
}

void foo(int x, int y = 10) {
 std::cout << "foo(int, int)" << std::endl;
}

int main() {
 foo(5); // ❌ 歧义:可以调用 foo(int) 或 foo(int, int)(用默认参数)
 return 0;
}

修复: 删除其中一个重载,或者改参数类型。


❓ 常见问题

Q:函数重载和 C 语言的函数有什么区别? A:C 语言不支持函数重载,因为 C 编译器的函数名修饰规则很简单(基本就是函数名本身)。

C++ 编译器会对函数名进行名称修饰(Name Mangling),把参数类型信息编码到函数名里,所以同名函数能共存。

Q:默认参数能是变量吗? A:可以,但必须是全局变量或静态变量(后面会学)。

CPP
int defaultY = 10;

void foo(int x, int y = defaultY) { // 可以是变量
// ...
}

Q:函数重载能提高程序运行效率吗? A:不能。函数重载是编译时特性(编译器根据实参类型选择函数),运行时效率和普通函数调用一样。

它提高的是开发效率(代码更简洁、易读)。


📖 小节


📝 作业

  1. 基础题 (Difficulty ⭐): 写一个重载函数 int max(int a, int b)double max(double a, double b),分别返回两个整数和两个浮点数的最大值。

  2. 进阶题 (Difficulty ⭐⭐): 写一个函数 void drawRectangle(int width, int height, char fillChar = '*'),打印一个矩形。

TEXT 📖 仅展示
输入:drawRectangle(5, 3, '#')
输出:
#####
#####
#####

(当不传 fillChar 时,用默认的 *

  1. 挑战题 (Difficulty ⭐⭐⭐): 写一个程序,实现"多功能计算器":
  2. 用函数重载实现 addsubtractmultiplydivide 函数,支持 intdouble 两种类型
  3. 用默认参数设置"保留小数位数"(默认 2 位)
  4. main 函数里测试所有函数

7. 🚀 下一步

学会了函数的高级用法,接下来我们学习 作用域与生命周期(第14课)—— 理解变量在哪里能被访问、能存在多久,这是理解程序行为的关键!

Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏