C++深入學(xué)習(xí)之徹底理清重載函數(shù)匹配
前言
前面我們講到了《函數(shù)重載》,有了函數(shù)重載之后,就需要確定某次調(diào)用需要選用哪個函數(shù)。這個過程可以稱之為函數(shù)匹配或者重載確定。大多數(shù)情況下,我們都很容易能夠確定某次調(diào)用需要選用哪個函數(shù),但事實上不盡然。但通過本文將徹底理清重載函數(shù)匹配
匹配過程
為便于說明,將函數(shù)匹配分為三個階段,確定候選函數(shù),確定可行函數(shù),確定最佳匹配函數(shù)。
確定候選函數(shù)
候選函數(shù)也就是和被調(diào)用的函數(shù)同名,并且其聲明在調(diào)用點可見。舉個簡單的例子。
假設(shè)有兩個文件,1.cpp和2.cpp,內(nèi)容分別如下:
1.cpp:
//函數(shù)1 void f(int a,short b) { cout<<"func0"<<endl; }
2.cpp:
#include<iostream> using namespace std; //函數(shù)2 void f(int a,double b) { cout<<"func1"<<endl; } //函數(shù)3 void f(int a, int b) { cout<< "func2"<<endl; } //函數(shù)4 void f1() { cout<<"func3"<<endl; } int main() { f(3,4.5); return 0; }
在這里,候選函數(shù)其實只有兩個,其中第一個函數(shù)在其調(diào)用點不可見,而第四個函數(shù)和被調(diào)用的函數(shù)不同名,因此這兩個都不是候選函數(shù)。
確定可行函數(shù)
可行函數(shù)指的是本次調(diào)用傳入的實參能夠被候選函數(shù)使用。它要滿足兩個條件, 一是形參數(shù)量和實參數(shù)量相同,二是每個實參的類型和對應(yīng)形參類型相同或者能夠轉(zhuǎn)換成形參的類型。
還是前面的例子,實參的個數(shù)和類型與第二個函數(shù)完全匹配,而在經(jīng)過算術(shù)轉(zhuǎn)換之后,也能夠與第三個函數(shù)匹配。
確定最佳匹配函數(shù)
最佳匹配的函數(shù)是最終調(diào)用的。最佳匹配最基本的思想是認(rèn)為,實參類型越接近,它們就越匹配。還是前面的例子,實參要與第三個函數(shù)匹配,需要進(jìn)行算術(shù)轉(zhuǎn)換,而與第二個函數(shù)完全匹配,因此第二個函數(shù)是最佳匹配函數(shù)。最終的運行結(jié)果如下:
func1
最佳匹配原則
一般來說,精確匹配肯定比需要類型轉(zhuǎn)換的匹配要更好,但是當(dāng)形參有多個,并且無法完全精確匹配的時候,要確定最佳匹配函數(shù)就有點困難了。
但是有下面的原則:
- 函數(shù)的每個實參的匹配都不能比其他可行函數(shù)更差
- 函數(shù)至少有一個實參的匹配要比其他可行函數(shù)更好
那么問題又來了,什么是更好,什么又是更差呢?編譯器將實參類型到形參類型的轉(zhuǎn)換劃分了等級:
1.精確匹配,包括實參類型和形參類型相同,實參從數(shù)組或函數(shù)轉(zhuǎn)換成對應(yīng)的指針類型,向?qū)崊⑻砑禹攲觕onst或從實參刪除頂層const
2.通過const轉(zhuǎn)換實現(xiàn)的匹配
3.通過類型提升實現(xiàn)的匹配
4.通過算數(shù)類型轉(zhuǎn)換實現(xiàn)的匹配
5.通過類類型轉(zhuǎn)換實現(xiàn)的匹配
等級越前,匹配也就越好。接下來對上面的內(nèi)容做一些解釋。
精確匹配
精確匹配比較容易理解。關(guān)于頂層const問題,可以參考《函數(shù)重載》
通過const轉(zhuǎn)換實現(xiàn)的匹配
所謂通過const轉(zhuǎn)換實現(xiàn)的匹配,指的是通過加const限定詞,能夠與可行函數(shù)精確匹配。例如:
#include <iostream> using namespace std; //函數(shù)1 /* int f(string &a) { cout<<"call function 1"<<endl; return 0; }*/ //函數(shù)2 int f(const string &a) { cout<<"call function 2"<<endl; return 0; } int main() { string test = "test"; f(test); return 0; }
在這里,test可以通過const轉(zhuǎn)換,從而匹配函數(shù)2,將能夠找到最佳匹配函數(shù)2(當(dāng)前情況它也只有一個可選了)。
運行結(jié)果如下:
call function 2
如果把函數(shù)1的注釋去掉再運行,就會發(fā)現(xiàn),雖然第一個調(diào)用既能匹配函數(shù)1,也能匹配函數(shù)2,但是由于匹配函數(shù)2的時候,需要const轉(zhuǎn)換,因此比精確匹配要差,最終,它會調(diào)用函數(shù)1。
去掉函數(shù)1的注釋后,運行結(jié)果如下:
call function 1
通過類型提升實現(xiàn)的匹配
關(guān)于類型提升,這里不多做介紹。簡單說明類型提升規(guī)則:
- float將提升到double
- char、short和相應(yīng)的signed、unsigned類型將提升到int
我們來看一個示例:
#include <iostream> using namespace std; //函數(shù)1 /* int f(short a) { cout<<"call function 1"<<endl; return 0; }*/ //函數(shù)2 int f(int a) { cout<<"call function 2"<<endl; return 0; } int main() { short a = 2; f(a); return 0; }
同樣地,我們暫時把函數(shù)1注釋掉。由于a是short類型,但是通過類型提升,可以轉(zhuǎn)換為int,因為它也能調(diào)用函數(shù)2。運行結(jié)果如下:
call function 2
但去掉函數(shù)1注釋后,由于精確匹配優(yōu)于通過類型提升的匹配,因此將會調(diào)用函數(shù)1,運行結(jié)果如下:
call function 1
通過算術(shù)類型轉(zhuǎn)換實現(xiàn)的匹配
short int和float,double等之間的轉(zhuǎn)換,都是算術(shù)類型之間的轉(zhuǎn)換。我們?nèi)匀粊砜匆粋€例子:
#include <iostream> using namespace std; //函數(shù)1 int f(int a) { cout<<"call function 1"<<endl; return 0; } //函數(shù)2 int f(double a) { cout<<"call function 2"<<endl; return 0; } int main() { short a = 2; f(a); return 0; }
在這里,short類型的a既可以通過類型提升轉(zhuǎn)換為int,也可以通過算術(shù)類型轉(zhuǎn)換成為double。這個時候,哪個才是最佳匹配呢?我們看運行結(jié)果:
call function 1
對于這個結(jié)果,并不意外,因為前面我們已經(jīng)說到,通過類型提升的轉(zhuǎn)換是優(yōu)于算術(shù)轉(zhuǎn)換的,因而函數(shù)1是它的最佳匹配函數(shù)。
通過類類型轉(zhuǎn)換實現(xiàn)的匹配
這里不多做介紹。我們也很容易理解。諸如父類和子類之間的轉(zhuǎn)換都是如此。
二義性示例
前面基本能夠找到最佳匹配,我們來看一個有多個可行函數(shù),最后卻沒有最佳匹配的情況。
#include<iostream> using namespace std; //函數(shù)1 void f(double a,int b) { cout<<"function 1"<<endl; } //函數(shù)2 void f(int a,double b) { cout<<"function 2"<<endl; } int main() { f(1,1); return 0; }
函數(shù)1和函數(shù)2都是可行函數(shù),但它們都沒有在任意一個參數(shù)上比對方更好,因此將會產(chǎn)生二義性,編譯時將會報錯:
error: call of overloaded ‘f(int, int)' is ambiguous
總結(jié)
- 調(diào)用重載函數(shù)時,應(yīng)當(dāng)避免強制類型轉(zhuǎn)換。
- 設(shè)計重載函數(shù)時應(yīng)避免可能產(chǎn)生的二義性。
- 如果無法找到可行函數(shù),編譯器將報錯。
- 設(shè)計重載函數(shù)的時候,希望避免需要用到上面的知識,而在定位問題時能夠利用上面的知識很快定位問題。
好了,以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。
相關(guān)文章
C++高并發(fā)內(nèi)存池的整體設(shè)計和實現(xiàn)思路
這篇文章主要介紹了C++高并發(fā)內(nèi)存池的整體設(shè)計和實現(xiàn)思路詳解,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-07-07C語言從基礎(chǔ)到進(jìn)階全面講解數(shù)組
數(shù)組是一組有序的數(shù)據(jù)的集合,數(shù)組中元素類型相同,由數(shù)組名和下標(biāo)唯一地確定,數(shù)組中數(shù)據(jù)不僅數(shù)據(jù)類型相同,而且在計算機內(nèi)存里連續(xù)存放,地址編號最低的存儲單元存放數(shù)組的起始元素,地址編號最高的存儲單元存放數(shù)組的最后一個元素2022-05-05C語言表達(dá)式求值中類型轉(zhuǎn)換和優(yōu)先級等問題詳解
表達(dá)式求值是一個常見的問題,可以用C語言實現(xiàn),下面這篇文章主要給大家介紹了關(guān)于C語言表達(dá)式求值中類型轉(zhuǎn)換和優(yōu)先級等問題的相關(guān)資料,文中通過實例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-05-05C++ push方法與push_back方法的使用與區(qū)別
這篇文章主要介紹了C++ push方法與push_back方法的使用與區(qū)別,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-12-12