溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

C++之如何徹底理清重載函數匹配

發布時間:2021-09-03 11:38:29 來源:億速云 閱讀:164 作者:小新 欄目:編程語言

小編給大家分享一下C++之如何徹底理清重載函數匹配,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!

匹配過程

為便于說明,將函數匹配分為三個階段,確定候選函數,確定可行函數,確定最佳匹配函數。

確定候選函數

候選函數也就是和被調用的函數同名,并且其聲明在調用點可見。舉個簡單的例子。

假設有兩個文件,1.cpp和2.cpp,內容分別如下:

1.cpp:

//函數1
 void f(int a,short b)
 {
 cout<<"func0"<<endl;
 }

2.cpp:

#include<iostream>
 using namespace std;
 //函數2
 void f(int a,double b)
 {
 cout<<"func1"<<endl;
 }
 //函數3
void f(int a, int b)
 {
 cout<< "func2"<<endl;
 }
 //函數4
 void f1()
 {
 cout<<"func3"<<endl;
 }
 int main()
 {
 f(3,4.5);
 return 0;
 }

在這里,候選函數其實只有兩個,其中第一個函數在其調用點不可見,而第四個函數和被調用的函數不同名,因此這兩個都不是候選函數。

確定可行函數

可行函數指的是本次調用傳入的實參能夠被候選函數使用。它要滿足兩個條件, 一是形參數量和實參數量相同,二是每個實參的類型和對應形參類型相同或者能夠轉換成形參的類型。

還是前面的例子,實參的個數和類型與第二個函數完全匹配,而在經過算術轉換之后,也能夠與第三個函數匹配。

確定最佳匹配函數

最佳匹配的函數是最終調用的。最佳匹配最基本的思想是認為,實參類型越接近,它們就越匹配。還是前面的例子,實參要與第三個函數匹配,需要進行算術轉換,而與第二個函數完全匹配,因此第二個函數是最佳匹配函數。最終的運行結果如下:

func1

最佳匹配原則

一般來說,精確匹配肯定比需要類型轉換的匹配要更好,但是當形參有多個,并且無法完全精確匹配的時候,要確定最佳匹配函數就有點困難了。

但是有下面的原則:

  • 函數的每個實參的匹配都不能比其他可行函數更差

  • 函數至少有一個實參的匹配要比其他可行函數更好

那么問題又來了,什么是更好,什么又是更差呢?編譯器將實參類型到形參類型的轉換劃分了等級:

1.精確匹配,包括實參類型和形參類型相同,實參從數組或函數轉換成對應的指針類型,向實參添加頂層const或從實參刪除頂層const

2.通過const轉換實現的匹配

3.通過類型提升實現的匹配

4.通過算數類型轉換實現的匹配

5.通過類類型轉換實現的匹配

等級越前,匹配也就越好。接下來對上面的內容做一些解釋。

精確匹配

精確匹配比較容易理解。關于頂層const問題,可以參考《函數重載》

通過const轉換實現的匹配

所謂通過const轉換實現的匹配,指的是通過加const限定詞,能夠與可行函數精確匹配。例如:

#include <iostream>
using namespace std;
//函數1
/*
int f(string &a)
{
 cout<<"call function 1"<<endl;
 return 0;
}*/
//函數2
int f(const string &a)
{
 cout<<"call function 2"<<endl;
 return 0;
}
int main()
{
 string test = "test";
 f(test);
 return 0;
}

在這里,test可以通過const轉換,從而匹配函數2,將能夠找到最佳匹配函數2(當前情況它也只有一個可選了)。
運行結果如下:

call function 2

如果把函數1的注釋去掉再運行,就會發現,雖然第一個調用既能匹配函數1,也能匹配函數2,但是由于匹配函數2的時候,需要const轉換,因此比精確匹配要差,最終,它會調用函數1。
去掉函數1的注釋后,運行結果如下:

call function 1

通過類型提升實現的匹配

關于類型提升,這里不多做介紹。簡單說明類型提升規則:

  • float將提升到double

  • char、short和相應的signed、unsigned類型將提升到int

我們來看一個示例:

#include <iostream>
using namespace std;
//函數1
/*
int f(short a)
{
 cout<<"call function 1"<<endl;
 return 0;
}*/
//函數2
int f(int a)
{
 cout<<"call function 2"<<endl;
 return 0;
}
int main()
{
 short a = 2;
 f(a);
 return 0;
}

同樣地,我們暫時把函數1注釋掉。由于a是short類型,但是通過類型提升,可以轉換為int,因為它也能調用函數2。運行結果如下:

call function 2

但去掉函數1注釋后,由于精確匹配優于通過類型提升的匹配,因此將會調用函數1,運行結果如下:

call function 1

通過算術類型轉換實現的匹配

short int和float,double等之間的轉換,都是算術類型之間的轉換。我們仍然來看一個例子:

#include <iostream>
using namespace std;
//函數1
int f(int a)
{
 cout<<"call function 1"<<endl;
 return 0;
}
//函數2
int f(double a)
{
 cout<<"call function 2"<<endl;
 return 0;
}
int main()
{
 short a = 2;
 f(a);
 return 0;
}

在這里,short類型的a既可以通過類型提升轉換為int,也可以通過算術類型轉換成為double。這個時候,哪個才是最佳匹配呢?我們看運行結果:

call function 1

對于這個結果,并不意外,因為前面我們已經說到,通過類型提升的轉換是優于算術轉換的,因而函數1是它的最佳匹配函數。

通過類類型轉換實現的匹配

這里不多做介紹。我們也很容易理解。諸如父類和子類之間的轉換都是如此。

二義性示例

前面基本能夠找到最佳匹配,我們來看一個有多個可行函數,最后卻沒有最佳匹配的情況。

#include<iostream>
using namespace std;
//函數1
void f(double a,int b)
{
 cout<<"function 1"<<endl;
}
//函數2
void f(int a,double b)
{
 cout<<"function 2"<<endl;
}
int main()
{
 f(1,1);
 return 0;
}

函數1和函數2都是可行函數,但它們都沒有在任意一個參數上比對方更好,因此將會產生二義性,編譯時將會報錯:

error: call of overloaded ‘f(int, int)' is ambiguous

總結

  • 調用重載函數時,應當避免強制類型轉換。

  • 設計重載函數時應避免可能產生的二義性。

  • 如果無法找到可行函數,編譯器將報錯。

  • 設計重載函數的時候,希望避免需要用到上面的知識,而在定位問題時能夠利用上面的知識很快定位問題。

以上是“C++之如何徹底理清重載函數匹配”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

c++
AI

亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女