More Effective C++ 21:通過重載避免隱式類型轉換

考慮以下類:

class UPInt
{
	public: 
	UPInt(); 
	UPInt(int value); 
	 ... 
};
const UPInt operator+(const UPInt& lhs, const UPInt& rhs);
UPInt upi1, upi2;
...
UPInt upi3 = upi1 + upi2;

現在考慮下面這些語句:

upi3 = upi1 + 10; 
upi3 = 10 + upi2;

這些語句也能夠成功運行。方法是通過建立臨時對象把整形數 10 轉換爲 UPInts

讓編譯器完成這種類型轉換是確實是很方便,但是建立臨時對象進行類型轉換工作是有開銷的,而我們不想承擔這種開銷。

大多數 C++程序員希望進行沒有臨時對象開銷的隱式類型轉換,我們如何能這麼做呢?

仔細想想,我們的目的不是真的要進行類型轉換,而是用 UPintint做爲參數調用 operator+。隱式類型轉換隻是用來達到目的的手段,但是我們不要混淆手段與目的。

如果我們想要把 UPIntint 對象相加,通過聲明如下幾個函數達到這個目的,每一個函數有不同的參數類型集:

const UPInt operator+(const UPInt& lhs, const UPInt& rhs); 
const UPInt operator+(const UPInt& lhs, int rhs);  
const UPInt operator+(int lhs, const UPInt& rhs);
UPInt upi1, upi2;
...
UPInt upi3 = upi1 + upi2;// 正確,沒有由 upi1 或 upi2生成的臨時對象
upi3 = upi1 + 10; // 正確, 沒有由 upi1 or 10生成的臨時對象 
upi3 = 10 + upi2; //正確, 沒有由 10 or upi2 生成的臨時對象。

但是注意,一旦你開始用函數重載來消除類型轉換,你就有可能這樣聲明函數,把自己陷入危險之中:

const UPInt operator+(int lhs, int rhs); // 錯誤!

這個想法是合情合理的。對於 UPIntint 類型,我們想要用所有可能的組合來重載operator 函數。上面只給出了三種重載函數,唯一漏掉的是帶有兩個 int 參數的 operator,所以我們想把它加上。

在 C++中有一條規則是每一個重載的 operator 必須帶有一個用戶定義類型的參數。int 不是用戶定義類型,所以我們不能重載 operator 成爲僅帶有此[int]類型參數的函數。

總結

利用重載避免臨時對象的方法不只是用在 operator 函數上。比如在大多數程序中,你想允許在所有能使用 string 對象的地方,也一樣可以使用 char*,反之亦然。任何帶有 stringchar*complex參數的函數可以採用重載方式來消除類型轉換。
不過,必須謹記 80-20 規則。沒有必要實現大量的重載函數,除非你有理由確信程序使用重載函數以後其整體效率會有顯著的提高。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章