C++ 函數重載二義性


說起函數重載,我不由得想起了C++的“多態”特性。多態又分為靜態(編譯時)多態和動態(運行時)多態,靜態多態即為函數重載,動態多態則是虛函數機制。虛函數水較深,先不討論,今天我們來看一下函數重載、作用以及要避免的一些坑(尤其是二義性錯誤)。

一、先來review一下 函數重載的概念

1. 函數名相同;

2. 形參類型和數量不同;

3. 不關返回值的事。

二、如何匹配要使用那個函數呢?

在C++ primary 中文5版 P217我們可以發現端倪。

1. 選定候選函數集 : ① 與被調用函數同名; ② 聲明在調用點可見。=》沒有,返回無匹配錯誤

2. 選定可行函數集:考察候選函數的參數列表,找出參數數量相同、且各個參數類型相同或者可以轉換為形參的函數;=》沒有,返回無匹配錯誤

3. 選出最佳匹配函數:層層選拔之后,如果幸存者函數有幾個的話(不太可能),我們就要找出最最最合適的那一個,怎么找?實參和形參類型最接近的那一個。=》沒有,返回無匹配錯誤

三、函數重載二義性

二義性是指在編譯過程中無法找出最匹配的函數,或者說編譯器在函數匹配過后還是有多個函數滿足要求,無法確定該執行那一個引發的錯誤。

具體表現:

1. 參數數目引發的歧義

1 int get(){
2     return 5;
3 }
4 int get(int a = 5){
5     return a;
6 }
7 //調用get()
//不給參數和有默認參數會造成歧義。

2. 參數隱式轉換引發的歧義

1 int get(int m){
2     return m;
3 }
4  
5 long get(long m){
6     return m;
7 }
//double d = 1.234;
//調用get(d);double既可以隱式轉換未long,也可以是int,或者說一般的數值類型之間都可以進行隱式類型轉換,故無法確定那一個更加匹配。
1 int get(int a){
2     return a;
3 }
4 int get(int &a){
5     return a;
6 }
7 //int m = 10;
8 //調用get(m)
//傳值和傳引用都可以完成調用,只不過值傳遞有拷貝的開銷,而引用傳遞不會有。

3. 類型型相關歧義(較深內容,不容易理解)

P517-520,艱澀難懂,需要自己琢磨。

另外,我發現在P517的一個例子,是錯誤的,並未發生歧義,不會導致運行錯誤。

 1 #include <iostream>
 2 #include <string>
 3 using namespace std;
 4 
 5 struct B;
 6 struct A {
 7     A() = default;
 8     A(const B&){
 9         //轉換B為A
10         cout << "A內部將B轉換為A" << endl;
11     };
12     //...
13     string name = "A";
14 };
15 
16 struct B {
17     B() = default;
18     operator A() const{
19         //類類型轉換,B->A
20         cout << "B 類類型轉換為 A" << endl;
21     };
22     //...
23     string name = "B";
24 };
25 
26 A f(const A&) {
27     //...
28 }
29 
30 int main()
31 {
32     B b;
33     A a = f(b);
34 }

(由g++運行)

四、如何避免/解決

一是我們要注意默認參數,二是要考慮類型轉換,使用explicit可以阻止隱式類型轉換。


 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM