第9课 - 函数重载分析(下)

1. 重载与指针

1.1 下面的函数指针将保存哪个函数的地址?

第9课 - 函数重载分析(下)_c++

1.2 函数重载遇上函数指针

将重载函数名赋值给函数指针时:

(1)根据重载规则挑选与函数指针参数列表一致的候选者

(2)严格匹配候选者的函数类型与函数指针的函数类型 (这里不仅需要匹配参数类型,还需要匹配返回值的类型,不然编译会出错!!!

第9课 - 函数重载分析(下)_c++_02第9课 - 函数重载分析(下)_函数重载_03

1 #include <stdio.h>
2 #include <string.h>
3
4 int func(int a)
5 {
6 return a;
7 }
8
9 int func(int a, int b)
10 {
11 return a + b;
12 }
13
14 int func(const char *s)
15 {
16 return strlen(s);
17 }
18
19 typedef int (*pFunc)(int); // 注意typedef后面的分号
20
21 int main(void)
22 {
23 int c = 0;
24 pFunc p = func;
25
26 c = p(1); // 根据pFunc指针的类型选择对应的重载函数
27
28 printf("c = %d\n", c);
29
30 return 0;
31 }

函数重载 VS 函数指针

函数重载 VS 函数指针

1.3 注意事项

(1)函数重载必然发生在同一个作用域中

(2)编译器需要用参数列表函数类型进行函数选择 【函数指针和参数的间接关系,函数指针中包含了返回值和参数类型的信息】

(3)无法直接通过函数名得到重载函数的入口地址

2. C++ 和 C 的相互调用

2.1 C++ 和 C 的相互调用

(1)实际工程中C++ 和C 代码相互调用是不可避免的

(2)C++ 编译器能够兼容C 语言的编译方式

(3)C++ 编译器会优先使用C++ 编译的方式

(4)extern 关键字能强制让C++ 编译器进行C 方式的编译

第9课 - 函数重载分析(下)_c++_04

【编程实验】C++ 调用C 函数

第9课 - 函数重载分析(下)_c++_02第9课 - 函数重载分析(下)_函数重载_03

int add(int a, int b);

add.h 第9课 - 函数重载分析(下)_c++_02第9课 - 函数重载分析(下)_函数重载_03

1 #include "add.h"
2
3 //该文件的编译,得到目标文件add.o
4 //gcc -c add.c
5
6 int add(int a, int b)
7 {
8 return a + b;
9 }

add.c

add.c 第9课 - 函数重载分析(下)_c++_02第9课 - 函数重载分析(下)_函数重载_03

1 #include <stdio.h>
2
3 //该文件的编译
4 //g++ main.cpp add.o
5
6 #ifdef __cplusplus
7 extern "C" {
8 #endif
9
10 //C++中以C的方式编译:将add的函数名就是目标名
11 #include "add.h"
12
13 #ifdef __cplusplus
14 }
15 #endif
16
17 int main()
18 {
19 int c = add(1, 2);
20
21 printf("c = %d\n", c); //3
22
23 return 0;
24 }

main.cpp

main.cpp

2.2 如何保证一段C代码只会以C的方式被编译?

(1)__cplusplus 是 C++ 编译器内置的标准宏定义

(2)__cplusplus 的意义:确保C代码以统一的C方式被编译成目标文件

第9课 - 函数重载分析(下)_编译器_11

【编程实验】C 调用 C++ 函数 (其中的C++ 函数由gcc 编译)

第9课 - 函数重载分析(下)_c++_02第9课 - 函数重载分析(下)_函数重载_03

 1 //该文件的编译,得到目标文件add.o
2 //g++ -c add.c
3
4 #ifdef __cplusplus
5 extern "C" {
6 #endif
7
8 //C++中以C的方式编译:add的函数名就是目标名
9 int add(int a, int b);
10
11 #ifdef __cplusplus
12 }
13 #endif

add.h 第9课 - 函数重载分析(下)_c++_02第9课 - 函数重载分析(下)_函数重载_03

1 #include "add.h"
2
3 //该文件的编译,得到目标文件add.o
4 //g++ -c add.c
5
6 #ifdef __cplusplus
7 extern "C" {
8 #endif
9
10 //C++中以C的方式编译:add的函数名就是目标名
11 int add(int a, int b)
12 {
13 return a + b;
14 }
15
16 #ifdef __cplusplus
17 }
18 #endif

add.cpp

add.cpp 第9课 - 函数重载分析(下)_c++_02第9课 - 函数重载分析(下)_函数重载_03

1 #include <stdio.h>
2 #include "add.h"
3 //编译方式:
4 //gcc main.c add.o
5 int main()
6 {
7 int c = add(1, 2);
8
9 printf("c = %d\n", c); //3
10
11 return 0;
12 }

main.c

main.c

【编程实验】C 调用 C++ 函数 (其中的C++ 函数由g++ 编译)

①假设别人提供了编译好的cpp的头文件和.o目标文件,但其中的函数是以C++方式编译的,很明显函数名是用C++方式命名的。我们的C文件里不方便使用这个的函数名。

②解决方案:做一个C++的封装层,对其中的函数进行一个封装,然后再用extern "c"编译这些封装层中的函数,最后就可以在C文件中使用了。


★ 其他人编写的C++代码,其中的函数名是用C++方式编译的,但只提供的.h和.o文件


1 int add(int a, int b);

复制代码
1 #include "add.h"
2
3 //编译命令:g++ -c add.cpp
4
5 int add(int a, int b)
6 {
7 return a + b;
8 }
复制代码

1 int addEx(int a, int b);

复制代码
1 #include "add.h"
2
3 //编译命令:
4 //g++ -c addEx.cpp
5
6 extern "C" int addEx(int a,int b)
7 {
8 return add(a, b);
9 }
复制代码

复制代码
1 #include <stdio.h>
2 #include "addEx.h"
3 //编译命令:
4 //gcc main.c addEx.0 add.o
5
6 int main()
7 {
8 int c = addEx(1, 2);
9
10 printf("c = %d\n", c); //3
11
12 return 0;
13 }
复制代码

main.c主文件

2.3 注意事项

(1)C++ 编译器不能以C 的方式编译重载函数,即如果在extern "C"块里有两个同名的函数里,则会编译失败。

(2)编译方式决定函数名被编译后的目标名

ⅰ:C++ 编译方式将函数名参数列表编译成目标名

ⅱ:C 编译方式只将函数名作为目标名进行编译

3. 小结

(1)函数重载是C++ 对 C 的一个重要升级

(2)函数重载通过函数参数列表区分不同的同名参数

(3)extern关键字能够实现C 和 C++ 的相互调用

(4)编译方式决定符号表中的函数名的最终目标名