在C原因中,一个函数不能与另一个函数重名,而在C++中,只要一个函数的参数列表与另一个函数的参数列表不完全相同,函数名就可以相同。而C++这一特点就是函数的重载。
同一个名字因为参数列表不同,展现了不同的结果,也叫静多态。
①函数名相同,函数参数列表不同(类型、个数、顺序) ②匹配原则1:严格匹配,找到再调用 ③匹配原则2:通过隐式类型转换寻求一个匹配,找到则调用 ④返回值类型不构成重载条件
/*要是放在C语言中,这段代码必然是编译不通过,而在C++中是合乎重载原则的*/#include <iostream>using namespace std;float abs(float i){ return (i >= 0 ? i : -i);}double abs(double i){ return (i >= 0 ? i : -i);}int abs(int i){ return (i >= 0 ? i : -i);}int main(){ /*abbiguous二义性*/ float i = abs(-5.5f);/*默认调用第一个abs*/ float j = abs(-4.4);/*默认调用第二个,如果注销掉第二个abs,编译时出错报二义性错误*/ cout << i << endl; cout << j << endl; /*浮点数默认大小(类型)*/ cout << "sizeof(4.5)=" << sizeof(4.5) << endl;/*default*/ cout << "sizeof(4.5f)=" << sizeof(4.5f) << endl; return 0;}注意: 重载时的二义性:如果计算机存在有两种隐式转换选择,计算机不会去选,而报二义性错误 eg1:double可以隐式转换为float或int,如果abs(-4.4)并且定义float与int分别作为参数的ads(),编译时则会产生二义性 eg2:double->int/float会产生两义性,int->long/double也会产生两义性。 即两个特例重载时需要注意。 为了避免重载中的二义性问题,使用时按所需强制转换,不要让计算机去自己选择
对于下面这段程序来说:
#include <iostream>using namespace std;//不设置,C++编译器默认倾轧void func(int a){cout<<"a = "<<a<<endl;}void func(char a){cout<<"a = "<<a<<endl;}void func(int a, char b){cout<<"a = "<<a<<endl<<"b = "<<b<<endl;}void func(char a, int b){cout<<"a = "<<a<<endl<<"b = "<<b<<endl;}int main(void){ int a = 10; char b = 'b'; func(a); func(b); func(a,b); func(b,a); return 0;}上面的程序在经过C++编译器编译时就类似于变成了下面这种写法,这种写法与其重载函数名以及参数类型有关:
#include <iostream>using namespace std;/*定义自动倾轧*/void func_i(int a){cout<<"a = "<<a<<endl;}void func_c(char a){cout<<"a = "<<a<<endl;}void func_ic(int a, char b){cout<<"a = "<<a<<endl<<"b = "<<b<<endl;}void func_ci(char a, int b){cout<<"a = "<<a<<endl<<"b = "<<b<<endl;}int main(void){ int a = 10; char b = 'b'; /*调用也自动倾轧*/ func_i(a); func_c(b); func_ic(a,b); func_ci(b,a); return 0;}在C++中,定义阶段与声明操作阶段均会进行倾轧(编译时倾轧),使用extern “C”,可以将某函数设置为不倾轧,可C++需要倾轧以支持重载,为什么弄一个不倾轧出来呢?
分析: 首先,函数声明时与定义时要么都倾轧,要么都不倾轧,必须得一一对应,否则会报函数找不到的错误。倾轧是编译时进行的,而对于C++要兼容C的问题,C++就必须兼容C的语法与C库(链接库),C库只在连链接时加入,不存在让C++编译器去倾轧的问题;而C头文件中声明的C库函数在调用时会倾轧,要想使用不参加倾轧的C库函数,C++中编译时就不能倾轧C的头文件中对于库函数的声明,即C库中已经不能修改不倾轧为倾轧,则必须将头文件中的声明也设置为不倾轧,以此与库中相互对应。如果查看C的标准头文件,可以发现其中有一个extern “C”,表示不倾轧C的函数声明。如下是string.h头文件中的一部分:
/*查看string.h,发现在函数声明之前,就对C++编译器的编译方式进行声明extern "C",即声明为:C++编译器在编译时不倾轧*/#ifndef _INC_STRING#define _INC_STRING#ifdef __cplusplus //如果是C++编译器就要进行不倾轧设置extern "C" {#endif... //函数声明等#ifdef __cplusplus//与上面匹配}#endif...分别查看不同集成承环境中的string.h文件,都是有对函数的extern “C”不倾轧限定:
举例说明:
#include <iostream>#include <string.h>using namespace std;extern "C"{ void func(int a){cout<<"a = "<<a<<endl;}}int main(void){ int a = 10; func(a); return 0;}由于定义时不倾轧,而调用时倾轧,经过C++编译器,其代码成为:
#include <iostream>using namespace std;/*定义时设置成不倾轧,在编译时,其函数名依旧相同*/void func(int a){cout<<"a = "<<a<<endl;}int main(void){ int a = 10; /*经C++编译器,函数名变为倾轧后的函数名*/ func_i(a); return 0;}这样的代码是不能够完成编译的。而要上面的函数能够正常调用,要么定义与调用时均遵循默认的倾轧,要么均设置为不倾轧,做法如下:
/*main.cpp*/#include<iostream>#include"func.h"using namespace std;int main(void){ int a = 10; func(a); return 0;}/*func.c*/#include<iostream>using namespace std;extern "C"{ void func(int a){cout<<"a = "<<a<<endl;}}/*func.h*/#ifndef FUNC_H_#define FUNC_H_extern "C" void func(int);//声明为不倾轧,调用根据声明调用,自然不倾轧#endif将函数声明与函数定义时,都设置为不倾轧即可。当然均不设置,采用默认也是可以编译通过的。但是声明与定义两部分只要任意一个设置为倾轧,另一个设置为不倾轧,编译就不能通过。
测试结果如下:
声明中不加extern “C”,编译出错: 声明中加extern “C”,编译不出错:
总之一句话,倾轧是C++为了实现函数重载而设计的,不倾轧的extern “C”则是为了兼容C而后实现的。我们编程一般犯不着对自定义的C++函数设置。
新闻热点
疑难解答
图片精选