c++之重载函数学习总结
一、C++中的函数重载: 1、函数重载的概念: 用同一个函数名定义不同的函数 当函数名和不同的参数搭配时函数的含义不同 注意:在c语言中是没有函数重载这个概念的。 代码示例演示: #include<stdio.h>#include<string.h>intfunc(intx){returnx;}intfunc(inta,intb){return(a+b);}intfunc(constchar*s){returnstrlen(s);}intmain(){return0;} 上面在c++编译器里面编译时没有问题的,如果放在c语言编译器里面编译是会报错的: root@txp-virtual-machine:/home/txp#gcctest5.ctest5.c:8:5:error:conflictingtypesfor‘func’intfunc(inta,intb)^test5.c:3:5:note:previousdefinitionof‘func’washereintfunc(intx)^test5.c:13:5:error:conflictingtypesfor‘func’intfunc(constchar*s)^test5.c:3:5:note:previousdefinitionof‘func’washereintfunc(intx) 所以说c语言里面不支持函数重载。 2、函数重载至少要满足下面的一个条件: 参数个数不同 参数类型不同 参数顺序不同 比如下面两个函数可以构造重载函数吗? intfunc(inta,constchar*s){returna;}intfunc(constchar*s,inta){returnstrlen(s)} 答案肯定是可以构造重载函数的,读者可以自己试试(这个比较好理解)。 3、当函数默认参数遇上函数重载会发生什么? 例如下面的两个函数: intfunc(inta,intb,intc=0){returna*b*c;}intfunc(inta,intb){returna+b;} 到底会发生啥,我们还是看下面这个实验: #include<stdio.h>intfunc(inta,intb,intc=0){returna*b*c;}intfunc(inta,intb){returna+b;}intmain(intargc,char*argv[]){intc=func(1,2);return0;} 运行结果: root@txp-virtual-machine:/home/txp#g++test5.cpptest5.cpp:Infunction‘intmain(int,char**)’:test5.cpp:16:22:error:callofoverloaded‘func(int,int)’isambiguousintc=func(1,2);^test5.cpp:16:22:note:candidatesare:test5.cpp:3:5:note:intfunc(int,int,int)intfunc(inta,intb,intc=0)^test5.cpp:8:5:note:intfunc(int,int)intfunc(inta,intb) 从上面报错的结果里面有一个单词ambiguous(意思是梦棱两可的),也就是说默认参数这种使用时不允许的。 4、C++编译器调用重载函数的准则: 将所有同名函数作为候选者 尝试寻找可行的候选函数: 精确匹配实参 通过默认参数能够匹配实参 通过默认类型转换匹配实参 匹配失败: 最终寻找到的候选函数不唯一,则出现二义性,编译失败 无法匹配所有候选者,函数未定义编译失败 5、函数重载的注意事项: 重载函数在本质上是相互独立的不同函数 重载函数的函数类型不同 函数返回值不能作为函数重载的依据 函数重载是由函数名和参数列表决定的 代码测试: #include<stdio.h>intadd(inta,intb)//int(int,int){returna+b;}intadd(inta,intb,intc)//int(int,int,int){returna+b+c;}intmain(){printf("%p\n",(int(*)(int,int))add);printf("%p\n",(int(*)(int,int,int))add);return0;} 运行结果: root@txp-virtual-machine:/home/txp#./a.out0x40052d0x400541 从输出结果我们可以看出这两个函数的入口地址不一样,这表明这两个函数是不同的函数。 6、小结: 函数重载是c++中引入的概念 函数重载的本质是相互独立的不同函数 c++中通过函数名和函数参数确定函数调用 二、重载函数进阶学习 1、重载与指针: 下面的函数指针将保存哪个函数的地址? intfunc(intx){returnx;}intfunc(inta,intb){returna+b;}intfunc(constchar*s){returnstrlen(s);}typedefint(*PFUNC)(inta);intc=0;PFUNCp=func;c=p(2)//到底选择哪个func函数 函数重载遇上函数指针: 将函数名赋值给函数指针时 根据重载规则跳线与函数指针参数列表一致的候选者 严格匹配候选者的函数类型与函数指针的函数类型 代码试验: #include<stdio.h>#include<string.h>intfunc(intx){returnx;}intfunc(inta,intb){returna+b;}intfunc(constchar*s){returnstrlen(s);}typedefint(*PFUNC)(inta);intmain(intargc,char*argv[]){intc=0;PFUNCp=func;c=p(2);printf("c=%d\n",c);return0;} 输出结果: root@txp-virtual-machine:/home/txp#./a.outc=2 从输出结果来看,很明显调用了第一个func函数。 2、注意: 函数重载必然发生在同一个作用域中 编译器需要用参数列表或者函数类型进行函数选择(也就是说碰到指针,要注意函数类型了) 无法直接通过函数名得到重载函数的入口地址,这里还是通过上面的例子演示一下: #include<stdio.h>intadd(inta,intb)//int(int,int){returna+b;}intadd(inta,intb,intc)//int(int,int,int){returna+b+c;}intmain(){printf("%p\n",add);printf("%p\n",add);return0;} 输出结果: root@txp-virtual-machine:/home/txp#g++test5.cpptest5.cpp:Infunction‘intmain()’:test5.cpp:15:23:error:overloadedfunctionwithnocontextualtypeinformationprintf("%p\n",add);^test5.cpp:16:23:error:overloadedfunctionwithnocontextualtypeinformationprintf("%p\n",add); 三、C++和C相互调用: 实际工程中C++和c代码相互调用是不可避免的 c++编译器能够兼容c语言的编译方式 c++编译器会优先使用c++编译的方式 extern关键字能够强制让C++编译器进行c方式的编译: extern"c"{} 1、下面进行一个c++中调用c函数,这里我在当前创建三个文件:add.c 、add.h 、main.cpp。内容分别如下: add.c内容: #include"add.h"intadd(inta,intb){returna+b;} add.h内容: intadd(inta,intb); 然后我用gcc编译编译生成add.o文件: root@txp-virtual-machine:/home/txp/add#vimadd.croot@txp-virtual-machine:/home/txp/add#vimadd.hroot@txp-virtual-machine:/home/txp/add#gcc-cadd.c-oadd.oroot@txp-virtual-machine:/home/txp/add#lsadd.cadd.hadd.o 然后main.cpp里面调用add.c #include<stdio.h>intmain(){intc=add(1,2);printf("c=%d\n",c);return0;} 输出结果: root@txp-virtual-machine:/home/txp/add#g++main.cppadd.o/tmp/ccqz3abQ.o:Infunction`main':main.cpp:(.text+0x13):undefinedreferenceto`add(int,int)'collect2:error:ldreturned1exitstatus 结果显示找不到这个函数,为了能够在c++里面调用c语言里面的函数,我们就要使用刚才上面讲的第四点了;这里我们先用nm命令来查看一下add.o文件里面是否生成符号表(有生成): root@txp-virtual-machine:/home/txp/add#nmadd.o0000000000000000Tadd 解决方法,main.cpp改成: #include<stdio.h>extern"c"{#include"add.h"}intmain(){intc=add(1,2);printf("c=%d\n",c);return0;} 输出结果: root@txp-virtual-machine:/home/txp/add#./a.outc=3 2、c中如何调用c++函数: 这里我把main.cpp的内容改成: extern"C"{intadd(inta,intb);}intadd(inta,intb){returna+b;} 编译输出: root@txp-virtual-machine:/home/txp/add#g++-cmain.cpp-otest.oroot@txp-virtual-machine:/home/txp/add#nm-stest.o0000000000000000Tadd add.c文件内容改成: #include<stdio.h>intmain(){intc=0;c=add(2,3);printf("c=%d\n",c);return0;} 输出结果: root@txp-virtual-machine:/home/txp/add#gccadd.ctest.oroot@txp-virtual-machine:/home/txp/add#./a.outc=5 3、如何保证一段c代码只会以c的方式被编译? 解决方法如下: __cplusplus是c++编译器内置的标准宏定义 __cplusplus的意义,确保c代码以统一的c方式被编译成目标文件 #ifdef__cplusplusextern"C"{#endif#ifdef__cplusplus}#endif 这里把main.cpp改成: #include<stdio.h>#ifdef__cplusplusextern"C"{#endif#include"add.h"#ifdef__cplusplus}#endifintmain(){intc=add(1,2);printf("c=%d\n",c);return0;} 输出结果: root@txp-virtual-machine:/home/txp/add#g++main.cppadd.oroot@txp-virtual-machine:/home/txp/add#./a.outc=3 4、注意事项 C++编译器不能以c的方式编译重载函数 编译方式决定函数名被编译后的目标名 c++编译方式将函数名和参数列表编译成目标名,这里举个例子main.cpp: intadd(inta,intb){returna+b;}intadd(inta,intb,intc){returna+b+c;} 编译输出: root@txp-virtual-machine:/home/txp/add#g++-cmain.cpp-otest.ooroot@txp-virtual-machine:/home/txp/add#nmtest.oo0000000000000000T_Z3addii0000000000000014T_Z3addiii 说明ii表示两个参数,iii表示三个参数 c编译方式只将函数名作为目标名进行编译,这里还是以main.cpp为例: extern"C"{intadd(inta,intb){returna+b;}intadd(inta,intb,intc){returna+b+c;}} 输出结果: root@txp-virtual-machine:/home/txp/add#g++-cmain.cpp-otest.oomain.cpp:Infunction‘intadd(int,int,int)’:main.cpp:8:29:error:declarationofCfunction‘intadd(int,int,int)’conflictswithintadd(inta,intb,intc)^main.cpp:3:5:error:previousdeclaration‘intadd(int,int)’hereintadd(inta,intb) 目标名起冲突所以报错。 5、小结: 函数重载是c++对c的一个重要升级 函数重载通过参数列表区分不同的同名函数 extern关键字能够实现c和c++的相互调用 编译方式决定符号表中的函数名的最终目标名 四、总结: 好了,今天的分享就到这里,如果文章中有错误或者不理解的地方,可以交流互动,一起进步。我是txp,下期见! 本文分享自微信公众号 - TXP嵌入式(txp1121518wo-)。如有侵权,请联系 support@oschina.cn 删除。本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。