---- 整理自狄泰软件唐佐林老师课程
文章目录
1. 重载的概念
- 同一个标识符在不同的上下文有不同的意义
1.1 函数重载
- 用 同一个函数名 定义不同的函数
- 当 函数名 和 不同的参数 搭配时函数的含义不同
1.2 函数重载的条件
- 至少满足下面的一个条件:
- 参数 个数 不同
- 参数 类型 不同
- 参数 顺序 不同
- 下面的两个函数可以构成重载函数吗?
- 可以构成,因为参数顺序不同
1.3 当函数默认参数遇上函数重载会发生什么?
#include <stdio.h>
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 t = func(1, 2);
return 0;
}
- 两个 func 函数都满足调用,因而编译报错
#include <stdio.h>
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 t = func(1);
return 0;
}
- 无法匹配所有的 func 函数,函数未定义,编译失败
1.4 编译器调用重载函数的准则
- 将所有 同名函数 作为候选者
- 尝试寻找可行的候选函数
-
- 通过 精确匹配 实参
-
- 通过 默认参数 能够匹配实参
-
- 通过 默认类型转换 匹配实参
-
- 匹配失败
- 最终寻找到的候选函数不唯一,则出现 二义性,编译失败
- 无法匹配所有的候选者,函数未定义,编译失败
1.5 函数重载的注意事项
- 重载函数在本质上是 相互独立的不同函数
- 重载函数的 函数类型不同
- 函数返回值不能作为函数重载的依据,函数重载和函数返回值无关
- 函数重载是由 函数名(相同)和 函数参数(不同:类型、个数、顺序)决定的
1.6 编程实验:函数重载的本质
#include <stdio.h>
int add(int a, int b) // 函数类型:int(int, int)
{
return a + b;
}
int add(int a, int b, int c) // 函数类型:int(int, int, int)
{
return a + b + c;
}
int main()
{
printf("%p\n", (int(*)(int, int))add );
printf("%p\n", (int(*)(int, int, int))add);
return 0;
}
1.7 下面的函数指针将保存哪个函数的地址?
- 将重载函数名赋值给函数指针时:
- 根据 重载规则 挑选与函数指针参数列表一致的候选者
- 严格匹配 候选者的函数类型与函数指针的函数类型(包括 返回类型 和 参数列表)
1.8 编程实验:函数重载vs函数指针
#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_A)(int a);
typedef int(*PFUNC_AB)(int a, int b);
typedef int(*PFUNC_S)(const char* s);
int main(int argc, char *argv[])
{
PFUNC_A p_a = func;
PFUNC_AB p_ab = func;
PFUNC_S p_s = func;
printf("%d\n", p_a(1) );
printf("%d\n", p_ab(1, 2) );
printf("%d\n", p_s("Hello") );
return 0;
}
#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 void(*PFUNC)(int a); // 匹配不上
int main(int argc, char *argv[])
{
PFUNC pfunc = func;
printf("%d\n", pfunc(1));
return 0;
}
1.9 注意
- 函数重载必然发生在 同一个作用域中
- 编译器需要用 参数列表 或 函数类型 进行函数选择
- 无法直接通过函数名得到重载函数的入口地址
2. C++ 和 C 相互调用
- C++ 编译器能够兼容 C 语言的编译方式
- C++ 编译器会优先使用 C++ 编译的方式
- extern关键字 能强制让 C++ 编译器进行 C 方式的编译
2.1 编程实验:C++ 调用 C 函数
- C++ 编译器会优先使用 C++ 编译的方式
// add.h
int add(int a, int b);
// add.c
#include "add.h"
int add(int a, int b)
{
return a + b;
}
// main.cpp
#include <stdio.h>
#include "add.h"
int main()
{
int c = add(1, 2);
printf("c = %d\n", c);
return 0;
}
// add.h
int add(int a, int b);
// add.c
#include "add.h"
// main.cpp
#include <stdio.h>
extern "C" {
#include "add.h"
}
int main()
{
int c = add(1, 2);
printf("c = %d\n", c);
return 0;
}
2.2 问题
- 如何保证一段 C 代码只会以 C 的方式被编译?
-
extern "C"
是 C++ 中的,C 语言不支持。
2.3 解决方案
__cplusplus
是 C++ 编译器内置的标准宏定义__cplusplus
的意义:确保 C 代码以统一的 C 方式被编译成目标文件
/* add.h */
int add(int a, int b);
/* add.c */
#include "add.h"
int add(int a, int b) {
return a + b;
}
/* main.cpp & main.c */
#include <stdio.h>
#ifdef __cplusplus
extern "C" {
#endif
#include "add.h"
#ifdef __cplusplus
}
#endif
int main()
{
int c = add(1, 2);
printf("c = %d\n", c);
return 0;
}
2.4 编程实验:C 调用 C++ 函数
- 注意事项:
- C++ 编译器不能以 C 的方式编译重载函数
- 编译方式决定函数名被编译后的目标名
- C++ 编译方式将 函数名 和 参数列表 编译成 目标名
- C 编译方式只将 函数名 编译成 目标名
// test.cpp
int add(int a, int b)
{
return a + b;
}
int add(int a, int b, int c)
{
return a + b + c;
}
// test.cpp
extern "C" {
int add(int a, int b)
{
return a + b;
}
int add(int a, int b, int c)
{
return a + b + c;
}
}
- C++ 通过 extern “C” 的方式强制以 C 的方式进行编译,两个函数的函数名都是 add,编译之后的目标名也还是 add,发生冲突,导致编译失败。