More Effective C++ 條款7 (轉)
條款7:不要過載overload &&, ||, or ,. :namespace prefix = o ns = "urn:schemas--com::office" />
與C一樣,C++使用布林簡化求值法(short-circuit evaluation)。這表示一旦確定了布林表示式的真假值,即使還有部分表示式沒有被測試,布林表示式也停止運算。例如:
char *p;
...
if ((p != 0) && (strlen(p) > 10)) ...
這裡不用擔心當p為空時strlen無法正確執行,因為如果p不等於0的測試失敗,strlen不會被。同樣:
int rangeCheck(int index)
{
if ((index < lowerBound) || (index > upperBound)) ...
...
}
如果index小於lowerBound,它不會與upperBound進行比較。
很早以前上述行為特性就被反覆灌輸給C和C++的員,所以他們都知道該特性。而且他們也依賴於簡短求值法來寫程式。例如在上述第一個程式碼中,當p為空指標時確保strlen不會被呼叫是很重要的,因為C++標準說(正如C標準所說)用空指標呼叫strlen,結果不確定。
C++允許根據定義的型別,來定製&&和||運算子。方法是過載operator&&
和operator||
,你能在全域性過載或每個類裡過載。然而如果你想使用這種方法,你必須知道你正在極大地改變遊戲規則。因為你以函式呼叫法替代了簡短計演算法。也就是說如果你過載了運算子&&,對於你來說程式碼是這樣的:
if (expression1 && expression2) ...
對於來說,等同於下面程式碼之一:
if (expression1.operator&&(expression2)) ...
// when operator&& is a
// member function
if (operator&&(expression1, expression2)) ...
// when operator&& is a
// global function
這好像沒有什麼不同,但是函式呼叫法與簡短求值法是絕對不同的。首先當函式被呼叫時,需要運算其所有引數,所以呼叫函式functions operator&&
和 operator||
時,兩個引數都需要計算,換言之,沒有采用簡短計演算法。第二是C++語言規範沒有定義函式引數的計算順序,所以沒有辦法知道表示式1與表示式2哪一個先計算。完全與具有從左引數到右引數計算順序的簡短計演算法相反。
因此如果你過載&&或||,就沒有辦法提供給程式設計師他們所期望和使用的行為特性,所以不要過載&&和||。
同樣的理由也適用於括號運算子,但是在我們深入研究它之前,我還是暫停一下,讓你不要太驚訝,“逗號運算子?哪有逗號運算子?”確實存在。
逗號運算子用於組成表示式,你經常在for迴圈的部分(update part)裡遇見它。例如下面來源於
Kernighan's and Ritchie's 經典書籍The C Programming Language 第二版(Prentice-Hall, 1988)的函式:
// reverse string s in place
void reverse(char s[])
{
for (int i = 0, j = strlen(s)-1;
i < j;
++i, --j) // 啊! 逗號運算子!
{
int c = s[i];
s[i] = s[j];
s[j] = c;
}
}
在for迴圈的最後一個部分裡,i被增加同時j被減少。在這裡使用逗號很方便,因為在最後一個部分裡只能使用一個表示式,分開表示式來改變i和j的值是不合法的。
對於內建型別&&和||,C++有一些規則來定義它們如何運算。與此相同,也有規則來定義逗號運算子的計算方法。一個包含逗號的表示式首先計算逗號左邊的表示式,然後計算逗號右邊的表示式;整個表示式的結果是逗號右邊表示式的值。所以在上述迴圈的最後部分裡,編譯器首先計算++i,然後是—j,逗號表示式的結果是--j。
也許你想為什麼你需要知道這些內容呢?因為你需要模仿這個行為特性,如果你想大膽地寫自己的逗號運算子函式。不幸的是你無法模仿。
如果你寫一個非成員函式operator,你不能保證左邊的表示式先於右邊的表示式計算,因為函式(operator)呼叫時兩個表示式做為引數被傳遞出去。但是你不能控制函式引數的計算順序。所以非成員函式的方法絕對不行。
剩下的只有寫成員函式operator的可能性了。即使這裡你也不能依靠於逗號左邊表示式先被計算的行為特性,因為編譯器不一定必須按此方法去計算。因此你不能過載逗號運算子,保證它的行為特性與其被料想的一樣。過載它是完全輕率的行為。
你可能正在想這個過載惡夢究竟有沒有完。畢竟如果你能過載逗號運算子,你還有什麼不能過載的呢?正如顯示的,存在一些限制,你不能過載下面的運算子:
. .* :: ?:
new delete sizeof typeid
static_cast dynamic_cast const_cast reinterpret_cast
你能過載:
operator new operator delete
operator new[] operator delete[]
+ - * / % ^ & | ~
! = += -= *= /= %=
^= &= |= <> >>= <<= == !=
<= >= && || ++ -- , ->* ->
() []
(有關new和delete還有operator
new
, operator
delete
, operator
new[]
, and operator
delete[]
的資訊參見條款8)
當然能過載這些運算子不是去過載的理由。運算子過載的目的是使程式更容易閱讀,書寫和理解,而不是用你的知識去迷惑其他人。如果你沒有一個好理由過載運算子,就不要過載。在遇到&&
, ||
, 和 ,
時,找到一個好理由是困難的,因為無論你怎麼努力,也不能讓它們的行為特性與所期望的一樣。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-990229/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Effective Modern C++ 系列之 條款2: autoC++
- Effective C++ 條款08_不止於此C++
- Effective c++條款11:在operator=中處理“自我賦值”C++賦值
- [讀書筆記][effective C++]條款30-inline的原理筆記C++inline
- 文獻學習——Making Deduction More Effective in SAT Solvers
- 學懂現代C++——《Effective Modern C++》之轉向現代C++C++
- effective C++ : CHAPTER 8C++APT
- Effective C++筆記C++筆記
- 【Effective Modern C++】索引C++索引
- effective C++筆記1C++筆記
- 《Effective C++》讀書筆記C++筆記
- Effective C++ 4.設計與宣告C++
- Effective C++ 筆記(3)資源管理C++筆記
- 條款01: 視C++為一個語言聯邦C++
- 《Effective C++》閱讀總結(三):資源管理C++
- 《Effective C++》第三版-1. 讓自己習慣C++(Accustoming Yourself to C++)C++
- 學懂現代C++——《Effective Modern C++》之型別推導和autoC++型別
- 條款05: 瞭解c++默默編寫並呼叫哪些函式C++函式
- [20180926]等待事件SQLNet more data from client 7.txt事件SQLclient
- 《Effective C++》第三版-5. 實現(Implementations)C++
- 讀完Java名著《Effective Java》: 我整理了這50條技巧Java
- 《Effective C++》閱讀總結(四): 設計、宣告與實現C++
- 《Effective C++》第三版-3. 資源管理(Resource Management)C++
- c++切面條題目C++
- 《Effective C++》第三版-4. 設計與宣告(Design and Declarations)C++
- 《Effective Python 第二版》第二條 遵循PEP8風格指南Python
- [C++之旅] 7 C++類和物件C++物件
- 《Effective C++》閱讀總結(二):類的構造、析構和賦值C++賦值
- 《看雪服務條款》
- 【C++】C++之型別轉換C++型別
- C++中的條件變數C++變數
- MORE_DETAIL_TECHAI
- TypeScript 之 More on FunctionsTypeScriptFunction
- More web function requests go online concurrently, and web service deployment is faster and more economical!WebFunctionGoAST
- 1-7 C++指標C++指標
- effective java 觀後感Java
- Vegetables need more practice.
- B-A Bit More Common
- Compare two or more repo directories