這幾天讀《C++編程規范http://book.douban.com/subject/1459007/》讀到第30條:“避免重載&&、||或,(逗號)”,一直不能完全吃透。今天才理解,原來是這麼回事:
內建的&&(邏輯與)、||(邏輯或)和,(逗號)操作符總是滿足以下性質:
從左至右對操作數進行求值;
對於&&操作符,若左操作數為假,那麼右操作數將不會求值,所以我們可以放心地寫下
[cpp]
if (p && p->next)
這樣的代碼而不用擔心p為0時p->next會先被求值;
類似地,對於||操作符,若左操作數為真,那麼右操作數將不會被求值。
上面第2點和第3點又叫做“短路求值法(Short Circut Evaluation)”。
如果我們重載了這三個運算符,會發生什麼呢?事實上,當一個操作符被重載時,編譯器就會將該操作符視為一個函數,而不是一個真正的操作符。一個函數的參數總是會被全部求值,而且其求值順序是未定義的。因此上述三個性質就全都不能滿足了!
考慮下面這個程序:
[cpp]
#include <iostream>
#include <string>
using namespace std;
string retString()
{
cout << "string" << endl;
return "hello";
}
int retInt()
{
cout << "int" << endl;
return 47;
}
int main()
{
retInt(), retString();
}
不管用什麼編譯器,只要其支持C++標准,程序的輸出都應該為
int
string
但如果重載了逗號操作符,像下面這樣:
[cpp]
void operator , (int a, const string &b)
{
}
用VS2010編譯後,程序就會先輸出string,再輸出int,可見操作數是從右向左求值的。
而如果對重載定義做少許的改動:
[cpp]
void operator , (const int &a, const string &b)
{
}
也就是把左操作數a的定義變成常量引用。那麼程序又會先輸出int再輸出string了。你可能會懷疑此時程序調用的是內建逗號操作符,那麼可以在重載定義中加一條cout輸出語句,就知道調用的其實還是重載操作符。只不過把參數的定義改了改,參數的求值順序就變了,是不是很“神奇”?
摘自 子子翔的專欄