重载的概念
重载(Overload)
.同一个标示符在不同的上下文有不同的意义
.如:
.“洗”和不同的词汇搭配后有不同的含义
--洗衣服,洗脸,洗脑,洗马桶,......
.“play”和不同的单词搭配后有不同的含义
--play chess,play piano,play basketball,......
C++中的函数重载
函数重载(Function Overload)
.用同一个函数名定义不同的函数
.当函数名和不同的参数搭配时函数的含义
例:
int func(int x) //一个int参数
{
return x;
}
int func(int a, int b) //两个int参数
{
return a + b;
}
int func(const char* s) //一个char*参数
{
return strlen(s);
}
int main(int argc, char *argv[]){
int c = 0;
c = func(1);
printf("c = %d\n",c); //调用第一个func函数,输出1
c= func(1,2);
printf("c = %d\n",c); //调用第二个func函数,输出3
c= func("12345");
printf("c = %d\n",c); //调用第三个func函数,输出5
......
}
函数重载至少满足下面的一个条件:
.参数个数不同
.参数类型不同
.参数顺序不同
例:
int func(int a,const char* s)
{
return a;
}
int func(const char* s,int a)
{
return strlen(s);
}
int main(int argc, char *argv[])
{
int c = 0;
c = func(1,"ab"); //调用第一个func,输出1
printf("c = %d\n",c);
c = func("ab",1); //调用第一个func,输出2
printf("c = %d\n",c);
......
}
当函数默认参数遇上函数重载会发生什么?
例:
int func(int a,int b,int c = 0)
{
return a + b + c;
}
int func(int a,int b)
{
return a + b;
}
int main(int argc, char *argv[])
{
int c = 0;
c = func(1,2); //此处编译报错 call of overloaded 'func(int, int)' is ambiguous
..... //candidates are:int func(int, int, int),int func(int, int)
} //存在二义性,调用失败,编译不能通过
如果使用了函数默认参数,就不要使用函数重载
如果决定重载函数,那么就不要使用函数默认参数
虽然C++支持int func(int a,int b,int c = 0) 和int func(int a,int b)这样的默认参数和函数重载同时存在,但最好不要同时使用,因为很容易引发二义性
编译器调用重载函数的准则:
1.将所有同名函数作为候选者
2.尝试寻找可行的候选函数
.精确匹配实参(个数,类型)
.通过默认参数能够匹配实参
.通过默认类型转换匹配实参 (三个条件同时进行不分先后)
例:int func(int a,int b,int c)
{
return a + b + c;
}
int func(int a,int b)
{
return a + b;
}
int main(int argc, char *argv[])
{
int c = 0;
c = func('a',2); //没有一个字符一个int这样的函数,字符型能默认转换为int,编译器会尝试通过默认类型转换匹配实参,
printf("c = %d\n",c); //发现将字符转换为int可以匹配func(int a,int b),于是编译器就会编译通过
.....
}
3.匹配失败
最终寻找到的可行候选函数不唯一,则出现二义性,编译失败
无法匹配所有候选者,函数未定义,编译失败
函数重载的注意事项
.重载函数在本质上是相互独立的不同函数
.重载函数的函数类型是不同的
.函数返回值不能作为函数重载的依据
函数重载是由函数名和参数列表决定的,跟返回值没有关系
函数重载与函数指针
.当使用重载函数名对函数指针进行赋值时
.根据重载规则挑选与函数指针参数列表一致的候选者
.严格匹配候选者的函数类型与函数指针的函数类型
例:
int func(int x) //函数类型int(int a)
{
return x;
}
int func(int a,int b)
{
return a + b;
}
typedef int(*PFUNC)(int a); //所指向的函数类型是int(int a)
int main(int argc, char *argv[])
{
int c = 0;
PFUNC p = func; //赋值时,1.根据重载规则挑选与函数指针参数列表(int a)一致的候选者( int func(int x) );
//2.严格匹配候选者的函数类型( int(int a) )与函数指针的函数类型( int(int a) ),可知类型匹配,所以此处的func一定是第一个func
c = p(1);
printf("c = %d\n",c);
......
}
C++和C的相互调用
.在项目中融合C++和C代码是实际工程中不可避免的
.虽然C++编译器能够兼容C语言的编程方式,但C++编译器会优先使用C++的方式进行编译
.利用extern关键字强制让C++编译器对代码进行C方式编译
C++调用C编写的函数
例:三个文件:main.cpp,add.c,add.h
修改main.cpp:
#include <stdio.h>
extern "C"
{
#include "add.h" //add函数在add.c中定义
}
int main()
{
printf("1 + 2 = %d\n", add(1, 2));
return 0;
}
C调用C++编写的函数
例:三个文件:main.c,add.cpp,add.h
修改add.cpp:
extern "C"
{
#include "add.h"
int add(int a, int b)
{
return a + b;
}
}
统一的解决方案
__cplusplus是C++编译器内置的标准宏定义
__cplusplus的意义:
.让C代码即可以通过C编译器的编译,也可以在C++编译器中以C方式编译
#ifdef __cplusplus
extern "C" {
#endif
//函数声明或函数定义
#ifdef __cplusplus
}
#endif
注意:C++编译器不能以C的方式编译多个重载函数
例:
#ifdef __cplusplus
extern "C" {
#endif
int func(int x)
{
return x;
}
int func(int a,int b) //报错:declaration of C function 'int func(int, int)' conflicts with previous declaration 'int func(int)' here
{ //因为C语言本来就不允许存在两个同名函数,C语言例没有重载函数概念
return a + b;
}
#ifdef __cplusplus
}
#endif
注意:extern “C”指的是标示符的是标示符的编译方式,不会干涉编译器的编译行为,所以在C++编译器下仍然是C++的行为不会有所改变。extern C是让C++编译按照C的方式对标识符进行编译,比如add函数编译后得到的名字就不是add了,而是其他,这个可以从汇编看出来
#ifdef __cplusplus
extern "C" {
#endif
void func()
{
const int a = 1;
int *p = (int *)&a;
*p = 5;
printf("a = %d\n", a); //输出还是1,const 还用c++编译器,所以无视extern直接进行C++的编译
}
#ifdef __cplusplus
}
#endif
小结
函数重载是C++对C语言的一个重要升级
韩式重载通过函数参数列表区分不同的同名函数
函数的返回值类型不是函数重载的依据
extern关键字能够实现C和C++的相互调用