函数重载
一、概念
C++ 允许在同一作用域中存在几个功能类似的同名函数,但这些同名函数的形参列表(参数个数 或 类型 或 顺序)必须不同
int Add(int left, int right)
{return left+right;
}double Add(double left, double right)
{return left+right;
}long Add(long left, long right)
{return left+right;
}int main()
{Add(10, 20);Add(10.0, 20.0);Add(10L, 20L);return 0;
}
二、名字修饰(Name Mangling) - 导致 C 和 C++ 代码不能直接相互调用
C/C++ 代码要运行起来,需要经历预处理、编译、汇编、链接这四个阶段,而 Name Mangling 是一种在编译期间将函数名重新修饰的机制,简单来说,就是编译器为了区分各个函数,通过 Name Mangling 保证在底层的全局唯一性
C 的名字修饰规则非常简单,只是在函数名前添加了下划线,这也是 C 不支持函数重载的原因
/** test.c*/
int Add(int left, int right);int main()
{Add(1, 2); // 编译器链接报错:error LNK2019: 无法解析的外部符号 _Add,该符号在函数 _main 中被引用return 0;
}
由于 C++ 要支持函数重载、命名空间、类等,使得其名字修饰规则比较复杂,不同编译器在底层的实现方式可能会有差异
int Add(int left, int right);
double Add(double left, double right);int main()
{Add(1, 2); // 编译器链接报错:error LNK2019: 无法解析的外部符号 "int __cdecl Add(int,int)" (?Add@@YAHHH@Z)Add(1.0, 2.0); // 编译器链接报错:error LNK2019: 无法解析的外部符号 "double cdecl Add(double,double)" (?Add@@YANNN@Z)return 0;
}
函数签名 | 修饰后名称 |
---|---|
int func(int) | ?func@@YAHH@Z |
float func(float) | ?func@@YAMM@Z |
int C::func(int) | ?func@C@@AAEHH@Z |
int C::C2::func(int) | ?func@C2@C@@AAEHH@Z |
int N::func(int) | ?func@N@@YAHH@Z |
int N::C::func(int) | ?func@C@N@@AAEHH@Z |
三、extern “C” - 解决 C 和 C++ 代码间相互调用问题
有时候,C++ 工程中需要将某些函数按照 C 规则进行编译,在函数前加 extern “C”,意思是告诉编译器,将该函数按照 C 规则进行编译
extern "C" int Add(int left, int right);int main()
{Add(1,2); // 链接时报错:error LNK2019: 无法解析的外部符号_Add,该符号在函数 _main 中被引用return 0;
}
C、C++ 混合调用