1、C++中的函數重載:c++
一、函數重載的概念:web
用同一個函數名定義不一樣的函數vim
當函數名和不一樣的參數搭配時函數的含義不一樣微信
注意:在c語言中是沒有函數重載這個概念的。編輯器
代碼示例演示:函數
#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);
}
int main()
{
return 0;
}
上面在c++編譯器裏面編譯時沒有問題的,若是放在c語言編譯器裏面編譯是會報錯的:學習
root@txp-virtual-machine:/home/txp# gcc test5.c
test5.c:8:5: error: conflicting types for ‘func’
int func(int a, int b)
^
test5.c:3:5: note: previous definition of ‘func’ was here
int func(int x)
^
test5.c:13:5: error: conflicting types for ‘func’
int func(const char* s)
^
test5.c:3:5: note: previous definition of ‘func’ was here
int func(int x)
因此說c語言裏面不支持函數重載。測試
二、函數重載至少要知足下面的一個條件:ui
參數個數不一樣url
參數類型不一樣
參數順序不一樣
好比下面兩個函數能夠構造重載函數嗎?
int func (int a,const char* s)
{
return a;
}
int func(const char*s,int a)
{
return strlen(s)
}
答案確定是能夠構造重載函數的,讀者能夠本身試試(這個比較好理解)。
三、當函數默認參數趕上函數重載會發生什麼?
例以下面的兩個函數:
int func(int a, int b, int c =0)
{
return a*b*c;
}
int func(int a, int b)
{
return a+b;
}
到底會發生啥,咱們仍是看下面這個實驗:
#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 c = func(1, 2);
return 0;
}
運行結果:
root@txp-virtual-machine:/home/txp# g++ test5.cpp
test5.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:
test5.cpp:3:5: note: int func(int, int, int)
int func(int a, int b, int c = 0)
^
test5.cpp:8:5: note: int func(int, int)
int func(int a, int b)
從上面報錯的結果裏面有一個單詞ambiguous(意思是夢棱兩可的),也就是說默認參數這種使用時不容許的。
四、C++編譯器調用重載函數的準則:
將全部同名函數做爲候選者
嘗試尋找可行的候選函數:
精確匹配實參
經過默認參數可以匹配實參
經過默認類型轉換匹配實參
匹配失敗:
最終尋找到的候選函數不惟一,則出現二義性,編譯失敗
沒法匹配全部候選者,函數未定義編譯失敗
五、函數重載的注意事項:
重載函數在本質上是相互獨立的不一樣函數
重載函數的函數類型不一樣
函數返回值不能做爲函數重載的依據
函數重載是由函數名和參數列表決定的
代碼測試:
#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;
}
運行結果:
root@txp-virtual-machine:/home/txp# ./a.out
0x40052d
0x400541
從輸出結果咱們能夠看出這兩個函數的入口地址不同,這代表這兩個函數是不一樣的函數。
六、小結:
函數重載是c++中引入的概念
函數重載的本質是相互獨立的不一樣函數
c++中經過函數名和函數參數肯定函數調用
2、重載函數進階學習
一、重載與指針:
下面的函數指針將保存哪一個函數的地址?
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) (int a);
int c =0;
PFUNC p = func;
c = p(2)//到底選擇哪一個func函數
函數重載趕上函數指針:
將函數名賦值給函數指針時
根據重載規則跳線與函數指針參數列表一致的候選者
嚴格匹配候選者的函數類型與函數指針的函數類型
代碼試驗:
#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)(int a);
int main(int argc,char *argv[])
{
int c =0;
PFUNC p =func;
c = p(2);
printf("c=%d\n",c);
return 0;
}
輸出結果:
root@txp-virtual-machine:/home/txp# ./a.out
c=2
從輸出結果來看,很明顯調用了第一個func函數。
二、注意:
函數重載必然發生在同一個做用域中
編譯器須要用參數列表或者函數類型進行函數選擇(也就是說碰到指針,要注意函數類型了)
沒法直接經過函數名獲得重載函數的入口地址,這裏仍是經過上面的例子演示一下:
#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", add);
printf("%p\n", add);
return 0;
}
輸出結果:
root@txp-virtual-machine:/home/txp# g++ test5.cpp
test5.cpp: In function ‘int main()’:
test5.cpp:15:23: error: overloaded function with no contextual type information
printf("%p\n", add);
^
test5.cpp:16:23: error: overloaded function with no contextual type information
printf("%p\n", add);
3、C++和C相互調用:
實際工程中C++和c代碼相互調用是不可避免的
c++編譯器可以兼容c語言的編譯方式
c++編譯器會優先使用c++編譯的方式
extern關鍵字可以強制讓C++編譯器進行c方式的編譯:
extern "c"
{
}
一、下面進行一個c++中調用c函數,這裏我在當前建立三個文件:add.c 、add.h 、main.cpp。內容分別以下:
add.c內容:
#include "add.h"
int add(int a, int b)
{
return a + b;
}
add.h內容:
int add(int a, int b);
而後我用gcc編譯編譯生成add.o文件:
root@txp-virtual-machine:/home/txp/add# vim add.c
root@txp-virtual-machine:/home/txp/add# vim add.h
root@txp-virtual-machine:/home/txp/add# gcc -c add.c -o add.o
root@txp-virtual-machine:/home/txp/add# ls
add.c add.h add.o
而後main.cpp裏面調用add.c
#include <stdio.h>
int main()
{
int c = add(1, 2);
printf("c = %d\n", c);
return 0;
}
輸出結果:
root@txp-virtual-machine:/home/txp/add# g++ main.cpp add.o
/tmp/ccqz3abQ.o: In function `main':
main.cpp:(.text+0x13): undefined reference to `add(int, int)'
collect2: error: ld returned 1 exit status
結果顯示找不到這個函數,爲了可以在c++裏面調用c語言裏面的函數,咱們就要使用剛纔上面講的第四點了;這裏咱們先用nm命令來查看一下add.o文件裏面是否生成符號表(有生成):
root@txp-virtual-machine:/home/txp/add# nm add.o
0000000000000000 T add
解決方法,main.cpp改爲:
#include <stdio.h>
extern "c"
{
#include "add.h"
}
int main()
{
int c = add(1, 2);
printf("c = %d\n", c);
return 0;
}
輸出結果:
root@txp-virtual-machine:/home/txp/add# ./a.out
c = 3
二、c中如何調用c++函數:
這裏我把main.cpp的內容改爲:
extern "C"
{
int add(int a, int b);
}
int add(int a, int b)
{
return a+b;
}
編譯輸出:
root@txp-virtual-machine:/home/txp/add# g++ -c main.cpp -o test.o
root@txp-virtual-machine:/home/txp/add# nm -s test.o
0000000000000000 T add
add.c文件內容改爲:
#include <stdio.h>
int main()
{
int c =0;
c = add(2,3);
printf("c=%d\n",c);
return 0;
}
輸出結果:
root@txp-virtual-machine:/home/txp/add# gcc add.c test.o
root@txp-virtual-machine:/home/txp/add# ./a.out
c=5
三、如何保證一段c代碼只會以c的方式被編譯?
解決方法以下:
__cplusplus是c++編譯器內置的標準宏定義
__cplusplus的意義,確保c代碼以統一的c方式被編譯成目標文件
#ifdef __cplusplus
extern "C"
{
#endif
#ifdef __cplusplus
}
#endif
這裏把main.cpp改爲:
#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;
}
輸出結果:
root@txp-virtual-machine:/home/txp/add# g++ main.cpp add.o
root@txp-virtual-machine:/home/txp/add# ./a.out
c = 3
四、注意事項
C++編譯器不能以c的方式編譯重載函數
編譯方式決定函數名被編譯後的目標名
c++編譯方式將函數名和參數列表編譯成目標名,這裏舉個例子main.cpp:
int add(int a, int b)
{
return a+b;
}
int add(int a, int b , int c)
{
return a+b+c;
}
編譯輸出:
root@txp-virtual-machine:/home/txp/add# g++ -c main.cpp -o test.oo
root@txp-virtual-machine:/home/txp/add# nm test.oo
0000000000000000 T _Z3addii
0000000000000014 T _Z3addiii
說明ii表示兩個參數,iii表示三個參數
c編譯方式只將函數名做爲目標名進行編譯,這裏仍是以main.cpp爲例:
extern "C"
{
int add(int a, int b)
{
return a+b;
}
int add(int a, int b , int c)
{
return a+b+c;
}
}
輸出結果:
root@txp-virtual-machine:/home/txp/add# g++ -c main.cpp -o test.oo
main.cpp: In function ‘int add(int, int, int)’:
main.cpp:8:29: error: declaration of C function ‘int add(int, int, int)’ conflicts with
int add(int a, int b , int c)
^
main.cpp:3:5: error: previous declaration ‘int add(int, int)’ here
int add(int a, int b)
目標名起衝突因此報錯。
五、小結:
函數重載是c++對c的一個重要升級
函數重載經過參數列表區分不一樣的同名函數
extern關鍵字可以實現c和c++的相互調用
-
編譯方式決定符號表中的函數名的最終目標名
4、總結:
好了,今天的分享就到這裏,若是文章中有錯誤或者不理解的地方,能夠交流互動,一塊兒進步。我是txp,下期見!
本文分享自微信公衆號 - TXP嵌入式(txp1121518wo-)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。