第9课 函数重载分析(下)
1. 函数重载与函数指针
(1)将重载函数名赋值给函数指针时
①根据重载规则挑选与函数指针参数列表一致的候选者
②严格匹配候选者的函数类型与函数指针的函数类型(所谓严格匹配,即函数参数及返回值都匹配)
【编程实验】函数重载 VS 函数指针 9-1.cpp
#include <stdio.h> #include <string.h> int func(int x) { return x; } int func(int a, int b) { return a + b; } int func(const char* s) { return strlen(s); } //声明函数指针 typedef int (*PFUNC)(int a); int main() { int c = 0; PFUNC p = func; //编译器将根据函数指针的类型去严格匹配对应的函数 //所以会找到int func(int);其他函数则匹配不成功 c = p(1); // printf("c = %d\n", c); //1 return 0; }
运行结果:
(2)注意事项
①函数重载必然发生在同一个作用域中(如,同一个类或同一命名空间中)
②编译器需要用参数列表或函数类型进行函数选择
③无法直接通过函数名得到重载函数的入口地址(因为编译结束后,C++会根据重载函数命名的规则重命名各个函数,而原来的函数名实际上是找不到的)
2. C++和C相互调用
(1)实际工作中C++和C代码相互调用是不可避免的
(2)C++编译器能够兼容C语言的编译方式
(3)C++编译器会优先使用C++编译的方式
(4)extern关键字能强制C++编译器进行C方式的编译
【编程实验】C++调用C函数 9-2
//add.h
int add(int a, int b);
//add.c
#include "add.h" //该文件的编译,得到目标文件add.o //gcc -c add.c int add(int a, int b) { return a + b; }
//main.cpp
#include <stdio.h> //该文件的编译 //g++ main.cpp add.o #ifdef __cplusplus extern "C" { #endif //C++中以C的方式编译:将add的函数名就是目标名 #include "add.h" #ifdef __cplusplus } #endif int main() { int c = add(1, 2); printf("c = %d\n", c); //3 return 0; }
运行结果:
3. 让C/C++代码只会以C的方式编译
(1)C++内置的标准宏:__cplusplus,可以确保C代码以统一的C方式编译
#ifdef __cplusplus extern "C" { #endif ......; //C/C++代码,将以C的方式编译 #ifdef __cplusplus } #endif
【编程实验】C调用C++函数(其中的C++函数己经被按C方式编译)
//add.h
//该文件的编译,得到目标文件add.o //g++ -c add.c #ifdef __cplusplus extern "C" { #endif //C++中以C的方式编译:add的函数名就是目标名 int add(int a, int b); #ifdef __cplusplus } #endif
//add.cpp
#include "add.h" //该文件的编译,得到目标文件add.o //g++ -c add.c #ifdef __cplusplus extern "C" { #endif //C++中以C的方式编译:add的函数名就是目标名 int add(int a, int b) { return a + b; } #ifdef __cplusplus } #endif
//main.c
#include <stdio.h> #include "add.h" //编译方式: //gcc main.c add.o int main() { int c = add(1, 2); printf("c = %d\n", c); //3 return 0; }
【编程实验】C调用C++函数(其中的C++函数是C++方式编译)
①假设别人提供了编译好的cpp的头文件和.o目标文件,但其中的函数是以C++方式编译的,很明显函数名是用C++方式命名的。我们的C文件里不方便使用这个的函数名。
②解决的方案是:做一个C++的封装层,对其中的函数进行一个封装,然后再用extern "c"编译这些封装层中的函数,最后就可以在C文件中使用。
▲其他人编写的C++代码,其中的函数名是用C++方式编译的,但只提供的.h和.o文件
//add.h
int add(int a, int b);
//add.cpp
#include "add.h" //编译命令:g++ -c add.cpp int add(int a, int b) { return a + b; }
▲我们的封装层
//addEx.h
int addEx(int a, int b);
//addEx.cpp
#include "add.h" //编译命令: //g++ -c addEx.cpp extern "C" int addEx(int a,int b) { return add(a, b); }
▲main.c演示的主文件
#include <stdio.h> #include "addEx.h" //编译命令: //gcc main.c addEx.0 add.o int main() { int c = addEx(1, 2); printf("c = %d\n", c); //3 return 0; }
(2)注意事项
①C++编译器不能以C的方式编译重载函数,即如果在extern "C"块里有两个同名的函数里,则会编译失败。
②编译方式决定函数名被编译后的目标名。
-
-
C++编译方式将函数名和参数列表编译成目标名
-
C编译方式只将函数名作为目标名进行编译
-
4. 小结
(1)函数重载是C++对C的一个重要升级
(2)函数重载通过函数参数列表区分不同的同名函数
(3)extern关键字能够实现C和C++的相互调用
(4)编译方式决定符号表中的函数名的最终目标名