4-1 運算子

c發表於2023-03-15

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;
    }
};

如果box2box3sum都是類物件,就可以編寫這樣的等式:

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)

  1. ||、&&

對於這兩個運運算元有一個特別的點就是,如果前半部分已經滿足/不滿足條件,那麼運運算元後面的部分將不再進行判斷,比如對於a||b,如果已經知道a的值判斷為1,那麼無論b是0還是1都不會對最終的結果產生影響,同理對於a&&b,如果已經知道a的值判斷為0,那麼b無論是1還是0都對最終的結果沒有影響。

  1. 執行順序

編譯器可以確保表示式中的運算優先順序,但是不會保證它的執行順序,比如

g()+f()*m()-n();

在這樣的式子裡編譯器不會確保先呼叫哪個函式,如果在這幾個函式裡有些有關聯的話,比如說m()函式依賴於g()函式得到的某個值,那麼建議最好分開寫,在獲得每一個函式的返回值後再進行最終的運算。

相關文章