從你開(kāi)始做C程序員那天開(kāi)始,你就記住increment的前綴形式有時(shí)叫做“增加然后取回”,后綴形式叫做“取回然后增加”。這兩句話(huà)非常重要,因為它們是increment前綴與后綴的形式上的規范。
// 前綴形式:增加然后取回值
UPInt& UPInt::operator++()
{
*this += 1; // 增加
return *this; // 取回值
}
// postfix form: fetch and increment
const UPInt UPInt::operator++(int)
{
UPInt oldValue = *this; // 取回值
++(*this); // 增加
return oldValue; // 返回被取回的值
}
后綴操作符函數沒(méi)有使用它的參數。它的參數只是用來(lái)區分前綴與后綴函數調用。如果你沒(méi)有在函數里使用參數,許多編譯器會(huì )顯示警告信息,很令人討厭。為了避免這些警告信息,一種經(jīng)常使用的方法時(shí)省略掉你不想使用的參數名稱(chēng);如上所示。
很明顯一個(gè)后綴increment必須返回一個(gè)對象(它返回的是增加前的值),但是為什么是const對象呢?假設不是const對象,下面的代碼就是正確的:
UPInt i;
i++++; // 兩次increment后綴
// 運算
這組代碼與下面的代碼相同:
i.operator++(0).operator++(0);
很明顯,第一個(gè)調用的operator++函數返回的對象調用了第二個(gè)operator++函數。
有兩個(gè)理由導致我們應該厭惡上述這種做法,第一是與內置類(lèi)型行為不一致。當設計一個(gè)類(lèi)遇到問(wèn)題時(shí),一個(gè)好的準則是使該類(lèi)的行為與int類(lèi)型一致。而int類(lèi)型不允許連續進(jìn)行兩次后綴increment:
int i;
i++++; // 錯誤!
第二個(gè)原因是使用兩次后綴increment所產(chǎn)生的結果與調用者期望的不一致。如上所示,第二次 調用operator++改變的值是第一次調用返回對象的值,而不是原始對象的值。因此如果:
i++++;
是合法的,i將僅僅增加了一次。這與人的直覺(jué)相違背,使人迷惑(對于int類(lèi)型和UPInt都是一樣),所以最好禁止這么做。
C++禁止int類(lèi)型這么做,同時(shí)你也必須禁止你自己寫(xiě)的類(lèi)有這樣的行為。最容易的方法是讓后綴increment 返回const對象。當編譯器遇到這樣的代碼:
i++++; // same as i.operator++(0).operator++(0);
它發(fā)現從第一個(gè)operator++函數返回的const對象又調用operator++函數,然而這個(gè)函數是一個(gè)non-const成員函數,所以const對象不能調用這個(gè)函數。如果你原來(lái)想過(guò)讓一個(gè)函數返回const對象沒(méi)有任何意義,現在你就知道有時(shí)還是有用的,后綴increment和decrement就是例子。(更多的例子參見(jiàn)Effective C++ 條款21)
如果你很關(guān)心效率問(wèn)題,當你第一次看到后綴increment函數時(shí), 你可能覺(jué)得有些問(wèn)題。這個(gè)函數必須建立一個(gè)臨時(shí)對象以做為它的返回值,(參見(jiàn)條款19),上述實(shí)現代碼建立了一個(gè)顯示的臨時(shí)對象(oldValue),這個(gè)臨時(shí)對象必須被構造并在最后被結構。前綴increment函數沒(méi)有這樣的臨時(shí)對象。由此得出一個(gè)令人驚訝的結論,如果僅為了提高代碼效率,UPInt的調用者應該盡量使用前綴increment,少用后綴increment,除非確實(shí)需要使用后綴increment。讓我們明確一下,當處理用戶(hù)定義的類(lèi)型時(shí),盡可能地使用前綴increment,因為它的效率較高。
我們再觀(guān)察一下后綴與前綴increment 操作符。它們除了返回值不同外,所完成的功能是一樣的,即值加一。簡(jiǎn)而言之,它們被認為功能一樣。那么你如何確保后綴increment和前綴increment的行為一致呢?當不同的程序員去維護和升級代碼時(shí),有什么能保證它們不會(huì )產(chǎn)生差異?除非你遵守上述代碼里的原則,這才能得到確保。這個(gè)原則是后綴increment和decrement應該根據它們的前綴形式來(lái)實(shí)現。你僅僅需要維護前綴版本,因為后綴形式自動(dòng)與前綴形式的行為一致。
正如你所看到的,掌握前綴和后綴increment和decrement是容易的。一旦了解了他們正確的返回值類(lèi)型以及后綴操作符應該以前綴操作符為基礎來(lái)實(shí)現的規則,就足夠了。
聯(lián)系客服