1 運運算元的過載
其實從一開始我們就已經見過運運算元的過載了,例如,運運算元*
用於地址,就可以得到儲存在這個地址中的值;用在兩個數字上時,得到的是乘積的效果。
過載運運算元需要使用被稱作運運算元函式的特殊函式形式,其格式如下
operator op(argument-list)
則operator +()
過載+運運算元,operator *()
過載*運運算元。
透過一個過載的示例來瞭解,現有一個Box
類,為它定義一個operate+()
成員函式來過載+運運算元,以便實現兩個物件的長寬相加。
class Box{
public:
int length;
int width;
Box operator+(const Box& box1){
Box box;
box.length=this->length+box1.length;
box.width=this->width+box1.width;
return box;
}
};
如果box2
和box3
、sum
都是類物件,就可以編寫這樣的等式:
sum=box2+box3;
//編譯器行為
sum=box2.operator+(box3);
可見過載的目的就在於改變其內部操作的效果,但要注意像運運算元優先順序這種是無法改變的。
2關聯性與優先順序
在一般表示式中先執行優先順序高的運運算元,再執行優先順序低的運運算元,比如a+b*c
先執行乘法再加法,但我們可以用()
將a+b關聯起來先執行。運運算元的優先順序有很長一串,很多時候不可能完全記住,C++Primer在這一方面的建議是:當你拿捏不準時,通通用括號來實現你想要的運算順序
3 注意事項
1.不建議在同一個表示式中改變它的值還同時引用它,這樣做不僅使程式碼的可讀性變差,而且容易出錯。
比如
int i=0;
cout<<i<<" "<<++i;
編譯器會發出警告Unsequenced modification and access to 'i'
,因為它不知道是該先輸出還是先進行++的操作。
為了增加我們對這一點的印象,再觀察這樣一個示例:
string s="helloworld";
auto beg = s.begin();
while(beg!=s.end()){
*beg = toupper(*beg++);
}
在這個大小寫轉換的程式碼中,我們希望先進行*beg = toupper(*beg)
,再進行beg++
的操作。但是由於我們在同一句話裡使用且改變beg
,編譯器很有可能會先進行beg++
的操作,再進行*beg = toupper(*beg)
。
- ||、&&
對於這兩個運運算元有一個特別的點就是,如果前半部分已經滿足/不滿足條件,那麼運運算元後面的部分將不再進行判斷,比如對於a||b
,如果已經知道a的值判斷為1,那麼無論b是0還是1都不會對最終的結果產生影響,同理對於a&&b
,如果已經知道a的值判斷為0,那麼b無論是1還是0都對最終的結果沒有影響。
- 執行順序
編譯器可以確保表示式中的運算優先順序,但是不會保證它的執行順序,比如
g()+f()*m()-n();
在這樣的式子裡編譯器不會確保先呼叫哪個函式,如果在這幾個函式裡有些有關聯的話,比如說m()
函式依賴於g()
函式得到的某個值,那麼建議最好分開寫,在獲得每一個函式的返回值後再進行最終的運算。