深入淺出C+函數重載
本文閱讀目錄
1、什麼是重載函數
2、函數重載的好處
3、編譯器如何解決命名衝突
4、extern "C"作用
什麼是函數重載
學過C語言的同學應該很清楚,在C語言中,同一個程序中是不能定義多個名稱相同的函數,否則編譯會報重定義的錯誤信息,但是C++中則允許定義多個名稱相同的函數,在C++中,這稱之為函數重載,讓我們來看看更官方一點的定義,函數重載是指在同一作用域內,可以有一組具有相同函數名,不同參數列表的函數,這組函數被稱為重載函數。此外需要注意的是,函數的返回值不構成重載條件。看下面幾組示例。
//類A和類B的兩個同名show()函數不構成重載
//因為兩個函數的作用域不一樣
classA
{
public:voidshow(intx){}
};
classB
{public:voidshow(doublex){}
};
//類A兩個同名show()函數不構成重載
//因為兩個函數的參數一樣,返回值類型不同不能構成重載
classA
{public:voidshow(intx){}intshow(intx){}
};
//類A兩個同名show()函數構成重載
//因為兩個同名函數作用域相同,且參數列表不一樣
classA
{public:voidshow(intx){}voidshow(doublex){}
};
註:重載函數的條件之一參數列表不同包括參數個數不同或者參數類型不同或者參數順序不同都可以。
函數重載的好處
先想想下面一個場景,如果一個程序要實現一組加法操作,既要能夠處理兩個整數,又要處理兩個字元串相加,你會如何做了? 如果是C語言,你必須為這組函數取不同的名字,如add_int, add_str等等, 是不是程序的可讀性不太好。如果是C++實現,由於其支持函數重載,因此可以用一個函數名add就OK了,這樣就避免了名字空間的污染,提高了程序的可讀性。
再想想,如果沒有函數重載機制,每個類只能存在一個構造函數(因為構造函數名字必須與類名相同),因此,要想以不同的方式實例化類對象,就會變的相當麻煩。
編譯器如何解決命名衝突
我們定義兩個重載函數如下圖所示,然後對生成的可執行利用objdump -d a.out命令進行反彙編觀察,可以看出,int add(int x, int y)編譯之後其函數簽名變為__Z3addii,函數float add(float x, float y)編譯之後其函數簽名變為__Z3addff, 不難發現,經過編譯之後,函數名變的不那麼單純了,會增加一些其它的信息進去,具體說來,編譯之後的函數名會包含返回值類型的信息、參數列表信息等等。這種技術叫命名修飾。
不同編譯器的命名修飾規則也不一樣,這裡就不深究了,我們只要知道C++中是通過這種機制來解決函數重載命名衝突的就好了。
extern "c" {}作用
通過前面分析可知,C++是一個面向對象語言,它支持函數重載,而C語言中並沒有函數重載,編譯器在編譯C++程序和C語言時的機制有些不同,比如說對於同一個函數int add(int x, int y);其函數名在C++中將被編譯為__Z3addii ;而在C語言中可能就是直接編譯為__add。
因此,如果C++中含有C語言代碼時,就可能會出問題。因為在編譯時C++編譯器對C代碼的函數也會進行名字修飾,函數名變了以後,將導致在C運行庫中找不到對應函數,發生鏈接錯誤。比如說對於以下代碼:
//print.cpp
intprintf(constchar*format,...);
intmain()
{printf("Hello world!");return;
}
看看編譯時發生了什麼:
bogon:0807lizhong$g++-oprintprint.cpp
Undefinedsymbolsforarchitecturex86_64:"printf(char const*, ...)",referencedfrom:_maininprint-f04c36.o
ld:symbol(s)notfoundforarchitecturex86_64
clang:error:linkercommandfailedwithexitcode1
bogon:0807lizhong$catprint.cpp
是不是,鏈接過程出現了錯誤,原因就是前面所說的,想想也是,printf函數是C標準庫定義的函數,其編譯時按照C語言編譯規則,函數名printf編譯為_printf(這裡只是假設,就是這麼個意思);而在print.cpp中,對printf的調用時按照C++編譯規則編譯,編譯成了_printf_XXX,鏈接的時候又怎麼能找得到呢?
因此為了防止C++編譯器對調用的C代碼在編譯時進行名字修飾,我們將C代碼用extern 「C」進行鏈接指定,告訴編譯器,不要對這部分代碼進行名字修飾,而是生成符合C規則的中間符號名。如下所示:
//print.cpp
extern "C"
{
intprintf(constchar*format,...);
}
intmain()
{printf("Hello world!");return;
}
好了,現在代碼就能夠正常運行了,我想大家也應該清楚extern "C"的作用了。


TAG:碼農有道 |
※以成員函數方式重載、以友元函數方式重載
※分數類,實現加減乘除操作符的重載(未考慮約數)
※我國重載鐵路橋樑轉體高度再次刷新
※Python的模塊導入和重載
※通過重載避免隱式類型轉換
※現階段輕卡向大貨廂重載發展成趨勢
※首個重載貨車車聯網數據服務發布
※《GTA5》五星逃亡,增重載具能幫你活下去嗎?撐的住五分鐘?
※科達發布重載球形轉檯攝像機
※const 注意事項(初始化,重載,參數和返回值)
※C++友元重載+運算符易錯點
※Python入門基礎之面向對象四:運算符重載
※獵鷹重載火箭之夢想啟示錄
※現代戰機的攻擊力,真和載彈量沒多大關係!在反艦時,只看有多少重載掛架
※江鈴大重載輕卡凱銳800HP即將實力亮相
※NASA希望其商業合作夥伴提出為月球表面提供重載荷的新技術
※Kotlin技術分享-運算符重載
※重載黃沙的渣土車剎車失靈,碰撞貨車後又衝出1公里,損失慘重,這可不是在玩漂移
※車速比同類車提升30% 江鈴凱銳重載金剛 重載輕卡界的「燕子李三」
※遼寧號航母的重載起飛點能實施滿油彈滑躍起飛