|
一、C++中的函数重载: 1、函数重载的概念:
代码示例演示: #include <stdio.h>; F0 v# {3 F/ F, C6 g( x/ X#include <string.h> int func(int x) { return x;# K! M: V- ]# Y } 8 \9 Q4 }) i$ M) w( ]7 E: d int func(int a, int b) { return(a+b); }, V: Y+ M8 p# W int func(const char* s)2 C9 ?# g4 U/ z% Y' D { return strlen(s);) M0 }/ B+ d' M# T }/ x; v1 x" _5 `! V8 K5 }! F0 Y4 _ int main()4 @+ x! p' a, e* p { & V5 f1 Q. r+ u" o, U/ w1 A0 L. O return 0; } 0 ? ~$ y* X3 ^5 o 上面在c++编译器里面编译时没有问题的,如果放在c语言编译器里面编译是会报错的: root@txp-virtual-machine:/home/txp# gcc test5.c. b! b' \+ {* F1 P+ {& ttest5.c:8:5: error: conflicting types for ‘func’ int func(int a, int b)! |! ~% K4 v; i$ H( k; x ^5 f" @6 _0 a+ d5 o test5.c:3:5: note: previous definition of ‘func’ was here int func(int x)$ Q$ ~* [9 |9 m {) g$ n ^9 M- n" x1 u. \* } test5.c:13:5: error: conflicting types for ‘func’3 O2 z M* o9 Y* `; |; t% _ int func(const char* s) ^ test5.c:3:5: note: previous definition of ‘func’ was here int func(int x) 6 p8 v0 _% ?, o8 y! J" i 所以说c语言里面不支持函数重载。 2、函数重载至少要满足下面的一个条件:
比如下面两个函数可以构造重载函数吗? int func (int a,const char* s){8 o) P6 z( s* |6 D return a;+ C! Q0 }) D6 @7 |- x, t w" G } & S3 c8 H: g8 L6 G* D int func(const char*s,int a)$ U% x' N" K6 G- \: H) U6 C0 x {3 V5 W0 o/ Z @2 j5 L: l return strlen(s)6 J+ ]8 a2 T" G( }' v6 S } 答案肯定是可以构造重载函数的,读者可以自己试试(这个比较好理解)。 3、当函数默认参数遇上函数重载会发生什么? 例如下面的两个函数: int func(int a, int b, int c =0)# y" I: p5 B7 D: C1 s/ M8 x{ return a*b*c; } int func(int a, int b) { return a+b;) J8 f# r/ U. b } $ z; ~: X' N+ S d 到底会发生啥,我们还是看下面这个实验: #include <stdio.h>3 `6 \& P# K. c& S- ~: ` int func(int a, int b, int c = 0)) i. l* H$ M: @, ]6 }( u( l' ` { return a * b * c;; ~ ]( @# W- @/ d4 c } 8 u. t8 i3 G0 Q1 X int func(int a, int b) { return a + b; }1 I4 Q% \- D/ h2 Q9 V- h7 G8 ] ' q) f+ _3 a& h8 i" G int main(int argc, char *argv[]) { int c = func(1, 2); `5 G; b( m7 k/ k3 g1 K return 0;6 g g( j# E! p2 a' Y8 ^ } 0 r p6 ? B$ x 运行结果: root@txp-virtual-machine:/home/txp# g++ test5.cpptest5.cpp: In function ‘int main(int, char**)’: test5.cpp:16:22: error: call of overloaded ‘func(int, int)’ is ambiguous int c = func(1, 2); ^ test5.cpp:16:22: note: candidates are:. u5 _9 V* K( c6 _- s0 a+ h$ W: J test5.cpp:3:5: note: int func(int, int, int) int func(int a, int b, int c = 0)/ Y# j! m1 K; [. A( f" _ ^ test5.cpp:8:5: note: int func(int, int)" i E3 L3 R# {+ ] int func(int a, int b)+ ~0 g# }0 J+ h& F6 f6 w' A& _ + _4 o: t! Q. c; \) T 从上面报错的结果里面有一个单词ambiguous(意思是梦棱两可的),也就是说默认参数这种使用时不允许的。 4、C++编译器调用重载函数的准则:
通过默认参数能够匹配实参 通过默认类型转换匹配实参
最终寻找到的候选函数不唯一,则出现二义性,编译失败 无法匹配所有候选者,函数未定义编译失败 5、函数重载的注意事项:
代码测试: #include <stdio.h>- ?; y! w4 X6 T* t5 f( G6 F! {3 Y) Y/ W int add(int a, int b) // int(int, int)2 J1 j, O9 d5 K, h { return a + b; }0 P4 G7 p1 z: A' A int add(int a, int b, int c) // int(int, int, int) { return a + b + c; }9 ]: R- V1 }! U; X* r6 N, g8 e" Z Z 5 ^( t1 Q9 _7 o) b' ?9 T int main() {8 E, n+ z/ p/ j! \/ |5 w% M; T printf("%p\n", (int(*)(int, int))add); printf("%p\n", (int(*)(int, int, int))add); V: R5 x* [2 \- K+ a+ Y+ v" Z 8 x' f6 G, x! U4 m% E return 0;, w5 X+ m% k3 v' `- W } 运行结果: root@txp-virtual-machine:/home/txp# ./a.out/ ]) J! M9 L4 J5 c0x40052d 0x400541 从输出结果我们可以看出这两个函数的入口地址不一样,这表明这两个函数是不同的函数。 6、小结:
二、重载函数进阶学习 1、重载与指针: 下面的函数指针将保存哪个函数的地址? int func(int x)( v1 J7 \0 \- _ [! {{5 L2 ?8 A2 V" d4 M% i) s return x; }$ f/ w6 G5 i8 H( j int func(int a, int b) {# P1 e. d( i2 Y return a+b;" @8 ~9 K7 k" i0 p }: @: {6 u2 x( h* N3 s( P+ R int func(const char* s) {4 n3 }5 z7 i3 n7 r0 a return strlen(s); }; R: `6 v- A2 m" f! b * n: [1 _5 _8 U, J& \$ X9 V4 z C0 b typedef int (*PFUNC) (int a); m" `' L+ z; ?" k" K! X. Q) M int c =0;1 u Q5 d S$ A* L B / }: i* w1 n) x PFUNC p = func;; }6 K: D' M( z9 W o' _/ e. l9 J! f! ] c = p(2)//到底选择哪个func函数 函数重载遇上函数指针:
代码试验: #include <stdio.h>#include <string.h> int func(int x) {! X; B3 I$ x8 F: [2 q j) F3 E/ J return x; } ' S. N0 j8 G* e+ {$ B4 ` int func(int a, int b) { return a+b; } ) m4 i! o2 J- w. s int func(const char* s) { return strlen(s); } typedef int(*PFUNC)(int a);: V$ L/ V2 V9 i0 s, h- u int main(int argc,char *argv[])5 k) [( C2 h, r6 s+ R8 u {, V# W9 O5 [* \/ |0 C. p7 @ int c =0; PFUNC p =func;% W0 S0 U- n* r c = p(2);2 F3 A: n: B f printf("c=%d\n",c);9 J: o) R5 T1 L( Q return 0;8 J/ A3 O4 r( W } 输出结果: root@txp-virtual-machine:/home/txp# ./a.out$ x9 h; w# M2 I& q! g2 @c=2 从输出结果来看,很明显调用了第一个func函数。 2、注意:
无法直接通过函数名得到重载函数的入口地址,这里还是通过上面的例子演示一下: #include <stdio.h>2 E; V; L: r: k% F' d* Z' x- \ B2 L% f4 b$ K2 u& q# c int add(int a, int b) // int(int, int)4 [, e2 D, Y4 D$ C1 t7 a { return a + b;3 s0 b# N, r: @' ? }: K" T. m! q1 h# x int add(int a, int b, int c) // int(int, int, int) {5 d o- ]& m( l' { return a + b + c;2 z: H* e+ q; m W" S } : t; h" P4 X/ o int main()9 N' d% y# Q7 K5 X. x! J {" w7 U# l& B0 O# C printf("%p\n", add);! o6 \9 u) I0 a- L% c2 s4 i printf("%p\n", add);1 |& c8 c/ O3 F c/ p0 V ; k+ j0 c& G* ?9 f+ g# i return 0; }% W4 ^+ Q# p9 F" @* t+ h+ o( ] 输出结果: root@txp-virtual-machine:/home/txp# g++ test5.cpp) x a' O5 ~# {test5.cpp: In function ‘int main()’: test5.cpp:15:23: error: overloaded function with no contextual type information printf("%p\n", add);. Q; D0 t! }' o$ ] ^9 S" W( U( W: D! Y test5.cpp:16:23: error: overloaded function with no contextual type information printf("%p\n", add);8 ]. V* a! h. J5 \7 h 三、C++和C相互调用:
extern关键字能够强制让C++编译器进行c方式的编译: extern "c"0 m2 s8 C# u q- ] s3 T j) _{; s" \# F, C' {* l4 h1 s5 \9 Z * S6 q A) g/ O! q" y5 b- T) A }! ~/ O" x. B5 L" A 1、下面进行一个c++中调用c函数,这里我在当前创建三个文件:add.c 、add.h 、main.cpp。内容分别如下: add.c内容: #include "add.h" int add(int a, int b), |5 ]- `; E5 b { return a + b; 3 k! Y2 |. w( o; N }2 c- W4 a G0 v8 ? k- K + U9 U: m; \- j: k- N# Z2 [ add.h内容: int add(int a, int b);然后我用gcc编译编译生成add.o文件: root@txp-virtual-machine:/home/txp/add# vim add.c0 j) b8 L3 P0 h9 H5 groot@txp-virtual-machine:/home/txp/add# vim add.h root@txp-virtual-machine:/home/txp/add# gcc -c add.c -o add.o9 ~3 B' t) i4 O root@txp-virtual-machine:/home/txp/add# ls5 z4 l$ }. J) L" w7 ?' C2 w add.c add.h add.o w$ A0 J6 b2 _" }5 \# ? O 然后main.cpp里面调用add.c #include <stdio.h>8 u4 b, M. V7 ^1 C9 r3 [1 sint main()# V9 K* U2 M1 C/ j { int c = add(1, 2); 5 v- a( f8 p) A printf("c = %d\n", c);7 B( V0 y+ O0 f! o+ H return 0;) w4 ]7 y$ V" t7 J }/ [( z f2 W/ ?$ H 输出结果: root@txp-virtual-machine:/home/txp/add# g++ main.cpp add.o [- S4 C6 t' t( Q/tmp/ccqz3abQ.o: In function `main': main.cpp .text+0x13): undefined reference to `add(int, int)'collect2: error: ld returned 1 exit status3 P- I/ @: h# O3 V ! n) T. ?$ D& Y& e& f5 E R 2 r9 W3 N* u) u& _ 结果显示找不到这个函数,为了能够在c++里面调用c语言里面的函数,我们就要使用刚才上面讲的第四点了;这里我们先用nm命令来查看一下add.o文件里面是否生成符号表(有生成): root@txp-virtual-machine:/home/txp/add# nm add.o0000000000000000 T add' N) C! [# r: g6 P" \5 m b . v; @3 a5 L# H, e7 r/ G 解决方法,main.cpp改成: #include <stdio.h>' J# T% F f+ U* m: G' Y' xextern "c"0 M3 f8 C$ C6 n6 d. ^& _ {9 Q- D1 x: P1 Z+ | D/ J9 E# p3 ^ #include "add.h"; ?* \/ C5 T1 A+ m% p: Q% |; I } 4 Y* T% N0 B) W! N) Q6 r* ` * Z, X# ~* T( I* [# @7 g- j int main() { int c = add(1, 2); 3 y( B/ [! Z2 ~$ O; s. ^. K printf("c = %d\n", c); + Q! E+ N7 }% R3 J* A( @) z return 0; }! o% Q4 g/ g* R9 j7 | ' K2 D/ |+ |- {6 B& Z- i3 w 输出结果: root@txp-virtual-machine:/home/txp/add# ./a.outc = 33 _5 y/ x6 u j# L4 l! V . y$ N& U' E( c; b 2、c中如何调用c++函数: 这里我把main.cpp的内容改成: extern "C"{ int add(int a, int b);& D% t- Y: F; n$ |$ H ' y, U. \% H6 O+ O5 w% [9 Z2 v }- z* h. R7 m# J4 X& ? P& l3 ?1 _1 R7 o" H2 } int add(int a, int b) { return a+b; / W" A# U5 k9 T" N2 a) o. F }+ C: ]9 \' Z% W 编译输出: root@txp-virtual-machine:/home/txp/add# g++ -c main.cpp -o test.oroot@txp-virtual-machine:/home/txp/add# nm -s test.o 0000000000000000 T add/ }0 B3 G% L9 q! Z 6 N V% a3 D6 p add.c文件内容改成: #include <stdio.h>7 Q1 R2 H1 U# Q+ A0 I8 g) fint main() Z4 l4 J$ U8 a. _( N, T { : \5 N% |9 \ w int c =0;2 o ?2 z S, [0 O9 g- I4 e c = add(2,3);+ }+ d( y6 D/ U& v* l printf("c=%d\n",c); return 0;5 j4 c. l( k( U5 X& C; X: U } 输出结果: root@txp-virtual-machine:/home/txp/add# gcc add.c test.o6 N6 ~5 m; D- ^# y1 i( v4 a+ `root@txp-virtual-machine:/home/txp/add# ./a.out9 Q3 X v* B# N c=5 3、如何保证一段c代码只会以c的方式被编译? 解决方法如下:
extern "C" { #endif3 i9 I9 r" B: x2 ^& y 7 i3 ]0 N( ~3 ]+ F7 Y+ S #ifdef __cplusplus } #endif 这里把main.cpp改成: #include <stdio.h>% l7 q; J+ g# Y4 c! \ #ifdef __cplusplus' ?/ k" H/ D% N ?8 } extern "C" {. X; k; h$ R) q) }7 d #endif #include "add.h"8 n9 M& f' b- J0 ^* \, }8 { + d% F0 d( m/ u% i/ e #ifdef __cplusplus }1 R- ]1 v3 Z! l. w" Z #endif: i2 C9 L7 R# Q3 ]: F8 { int main()& k4 S$ g T' v { int c = add(1, 2); ' s/ ?) T0 |$ b6 M1 ]! @* y, s printf("c = %d\n", c);. Q1 q2 ~& r( ?, o6 L. ?* f return 0; } 输出结果: root@txp-virtual-machine:/home/txp/add# g++ main.cpp add.oroot@txp-virtual-machine:/home/txp/add# ./a.out4 r- s4 k, ]' D c = 3$ ` e1 B9 U) a$ v6 t3 b0 t! O 4、注意事项
{* F; s* E* v# ~" e return a+b;5 h" F% i7 W% u/ w8 H9 z/ o }6 O5 \7 _0 G2 v$ K4 A4 s/ L' @+ L5 L int add(int a, int b , int c) {3 y, `/ k: Q$ J8 T1 w+ ^ return a+b+c; } 编译输出: root@txp-virtual-machine:/home/txp/add# g++ -c main.cpp -o test.ooroot@txp-virtual-machine:/home/txp/add# nm test.oo6 J; ?0 y) ~' u2 @+ T. o& Z( i 0000000000000000 T _Z3addii 0000000000000014 T _Z3addiii 说明ii表示两个参数,iii表示三个参数
{3 z& Z/ m( T5 F# {/ H- C: g) v U- p* S3 { int add(int a, int b) {1 |; C, L. I ?% L return a+b; }- `4 n7 G) O0 {' H/ ` 4 M( q$ `3 H' f6 S, Y# j: f$ D int add(int a, int b , int c) {& L( @4 d" n$ _$ l$ ^ return a+b+c; }9 }4 Z- R: o* y. w, f& Y+ S' p }* T$ [- p( R, q" m 输出结果: root@txp-virtual-machine:/home/txp/add# g++ -c main.cpp -o test.oomain.cpp: In function ‘int add(int, int, int)’:1 K# X4 H3 Y5 e main.cpp:8:29: error: declaration of C function ‘int add(int, int, int)’ conflicts with int add(int a, int b , int c)" h# _! ^7 ]- [, G3 ?7 t4 ] ^: Y3 A. \2 N; x% F O. ` main.cpp:3:5: error: previous declaration ‘int add(int, int)’ here. b+ M j% J* B: h7 n' d int add(int a, int b) 目标名起冲突所以报错。 5、小结:
四、总结: + Q" [$ ~- H C$ [6 B 好了,今天的分享就到这里,如果文章中有错误或者不理解的地方,可以交流互动,一起进步。 |
微信公众号
手机版