提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
什么是函数重载?
函数重载(Function Overloading) 是 C++ 的核心特性之一,允许在同一作用域内定义多个同名函数,只要 参数个数不同或 类型不同 或 参数类型顺序不同。通过这种方式,相同的函数名可以根据不同的参数类型或数量执行不同的逻辑,提升代码的可读性和灵活性。
一、函数重载的规则与类型
1、函数名相同
2、参数列表不同:至少满足以下条件之一:
2.1 参数类型不同
void bilili(int value) { /*...*/ }
void bilili(double value) { /*...*/ }
2.2 参数个数不同
void f(){ /*...*/ }
void f(int a){ /*...*/ }
2.3 参数类型顺序不同
void f(int a, char b){ /*...*/ }
void f(char b, int a){ /*...*/ }
2.4 特殊场景
如果参数是引用或指针,const
可以参与重载:
void process(int& x); // 非 const 引用
void process(const int& x); // const 引用(构成重载)
类的成员函数可以通过 const
修饰符重载:
class Data {
public:
void get() { /* 非 const 版本 */ }
void get() const { /* const 版本 */ }
};
3.返回类型无关:仅返回类型不同无法构成重载。
二、调用歧义
尽管函数重载灵活,但某些情况下编译器无法确定调用哪个函数,导致歧义错误:
1. 隐式类型转换冲突:
void calc(int x);
void calc(double x);
calc(10.5f); // 错误!float 可隐式转为 int 或 double,编译器无法抉择
2. 默认参数干扰:
void save(int a, int b = 0);
void save(int a);
save(5); // 错误!两个函数均匹配
3. 模板与非模板函数冲突:
template <typename T>
void process(T x) { /*...*/ }
void process(int x) { /*...*/ }
process(10); // 调用非模板函数(更匹配)
process<>(10); // 强制调用模板函数
三、函数重载的作用域限制
函数重载必须发生在同一作用域内。若在子作用域(如类或命名空间)中定义同名函数,会隐藏父作用域的同名函数,而非重载:
void globalFunc(int x); // 全局作用域
namespace MyLib {
void globalFunc(double x); // 隐藏全局的 globalFunc(int)
void test() {
globalFunc(5); // 错误!全局的 int 版本被隐藏,只能调用 double 版本
}
}
四、为什么 C++ 支持函数重载,而 C 语言不支持?
编译器在运行代码时会经历 预处理->编译->汇编->链接 四个过程,而在这个过程中
C 语言的函数符号规则:
C 编译器在生成目标代码时,仅使用函数名作为符号标识。例如:
// C 代码
void func(int x); // 符号名:func
void func(double x); // 符号名:func(冲突!)
链接器发现两个同名函数,直接报错。
C++语言的函数符号规则:
C++ 编译器通过名称修饰将函数名、参数类型等信息编码为唯一符号。例如:
// C++ 代码
void func(int x); // 符号名:_Z4funci
void func(double x); // 符号名:_Z4funcPd
链接器根据修饰后的符号区分不同重载版本。
总结起来就是:1.c语言用函数名去查找 2.c++用修饰后的函数名去查找
总结
优势:提升代码复用性,简化接口设计。
核心规则:参数列表必须不同,作用域一致。
C/C++ 差异:C++ 通过名称修饰支持重载,C 语言因符号规则限制无法实现。