C++对C语言的扩展--函数重载
1 函数重载
函数重载(Function Overload):用同一个函数名定义不同的函数,当函数名和不同的参数搭配时函数的含义不同。
1.1 重载规则
- 函数名相同
- 参数个数不同,参数的类型不同,参数顺序不同,均可构成重载
- 返回值类型不同不可以构成重载函数
void func(int a);
void func(char a);
void func(int a, char b);
void func(char a, int b);
char func(int a); // 错误,与第一个函数冲突
1.2 调用准则
- 严格匹配,找到则调用。
- 通过隐式转换寻求一个匹配,找到则调用。
#include <iostream>
using namespace std;
void func(double a)
{
cout << a << endl;
}
void func(int a)
{
cout << a << endl;
}
int main()
{
func(1); // func(int)
func(1.1); // func(double)
func('a'); // func(int)
func(1.11f); // func(double)
return 0;
}
编译器调用重载函数的准则:
- 将所有同名函数作为候选者
- 尝试寻找可行的候选函数
- 精确匹配实参
- 通过默认参数能够匹配实参
- 通过默认类型转换匹配实参
- 匹配失败
- 最终寻找到的可行候选函数不唯一,则出现二义性,编译失败。
- 无法匹配所有候选者,函数未定义,编译失败。
1.3 重载底层实现(name mangling)
C++利用 name mangling(倾轧)技术,来改名函数名,区分参数不同的同名函数。
实现原理:用 v c i f l d 表示 void char int float long double 及其引用。
void func(char a); // func_c(char a);
void func(char a, int b, double c); // func_cid(char a, int b, double c);
1.4 函数重载与函数默认参数
一个函数,不能既作重载,又作默认参数的函数。当你少写一个参数时,系统 无法确认是重载还是默认参数。
#include <iostream>
using namespace std;
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 c = 0;
c = func(1, 2); // 错误,存在二义性
cout << c << endl;
return 0;
}
1.5 函数重载和函数指针结合
/*
函数重载与函数指针
当使⽤用重载函数名对函数指针进⾏行赋值时
根据重载规则挑选与函数指针参数列表一致的候选者
严格匹配候选者的函数类型与函数指针的函数类型
*/
#include <iostream>
#include <string.h>
using namespace std;
int func(int x) // int(int a)
{
return x;
}
int func(int a, int b) // int(int a, int b)
{
return a*b;
}
int func(const char *a)
{
return strlen(s);
}
typedef int(*PFUNC)(int a); // int(*)(int a)
typedef int(*PFUNC2)(int a, int b); // int(*)(int a, int b)
int main()
{
int c = 0;
PFUNC P = func;
c = p(1);
cout << c << endl;
PFUNC2 p2 = func;
c = p2(1, 2);
cout << c << endl;
return 0;
}
1.6 函数重载总结
- 重载函数在本质上是相互独立的不同函数。
- 函数的函数类型是不同的 。
- 函数返回值不能作为函数重载的依据 。
- 函数重载是由函数名和参数列表决定的。
1.7 函数重载注意事项
- 函数重载碰到默认参数,注意避免二义性出现。
- 形参加const和不加const的引用可以作为重载条件
#include <iostream>
using namespace std;
void func(int &a) // int &a = 10; 不合法
{
cout << "func(int &a)调用" << endl;
}
void func(const int &a) // const int &a = 10; 合法
{
cout << "func(const int &a)调用" << endl;
}
int main()
{
int a = 10;
func(a); // func(int &a)调用
func(10); // func(const int &a)调用
return 0;
}
2 扩展–函数指针的基本语法
// 方法一:
// 声明一个函数类型
typedef void (myTypeFunc)(int a, int b);
// 定义一个函数指针
myTypeFunc *myfuncp = NULL; // 定义一个函数指针,这个指针指向函数的入口地址
// 方法二:
// 声明一个函数指针类型
typedef void (*myPTypeFunc)(int a, int b); // 声明了一个函数指针的数据类型
// 定义一个函数指针
myPTypeFunc fp = NULL; // 通过函数指针类型定义了一个函数指针
// 方法三:
// 定义一个函数指针 变量
void (*myVarPFunc)(int a, int b)