轉載:C++自增運算符的探索

轉自:http://www.cnblogs.com/chenyuming507950417/archive/2012/04/19/2456966.html
複製代碼
#include <iostream>
using namespace std;

int main()
{
    int a=5;
    int b=++++a;
    cout<<"b= "<<b<<"\t"<<"a= "<<a<<endl;

    return 0;
}
複製代碼

運行結果:

b= 7    a= 7

複製代碼
#include <iostream>
using namespace std;

int main()
{
    int a=5;
    int b=(a++)++;
    cout<<"b= "<<b<<"\t"<<"a= "<<a<<endl;

    return 0;
}
複製代碼

運行結果:

發生編譯錯誤:error C2105: '++' needs l-value

      我們知道:自增運算符++是結合方向是自右自左(VC++6.0),所以++++a也在寫成++(++)a。根據++結合性,a++++肯定是錯誤的。至於(a++)++和++a++是否會發生錯誤,分析a++與++a後自會知道。

a++與++a的差別:

    (1)在運算過程中,先將對象進行遞增修改,而後返回該對象(其實就是對象的引用)的叫前遞增運算++a。在運算符重載函數中採用返回對象引用的方式編寫。

    (2)在運算過程中,先返回原有對象的值,而後進行對象遞增運算的叫後遞增運算a++。在運算符重載函數中採用值返回的方式編寫,重載函數的內部實現必須創建一個用於臨時存儲原有對象值的對象,函數返回的時候就是返回該臨時對象。

    現在來分析下上面提出的問題:對於 (a++)++,先運算(a++),但(a++)返回的不是引用,而是原有a值的一個拷貝,而此時的拷貝不再是一個變量,還是一個常量,故不能當作左值繼續參加括號外部的++運算。至於++a++,即++(a++),同樣不能編譯通過,原因是同樣的道理。

自增運算符++的重載:

     在編寫運算符重載函數的時候該如何區分前遞增運算符重載函數與後遞增運算符重載函數呢?方法就是:在後遞增運算符重載函數的參數中多加一個int標識,標記爲後遞增運算符重載函數。

複製代碼
#include <iostream>
using namespace std;

class Test
{
public:
    Test(int a=0)
    {
        Test::a=a;
    }
    friend Test& operator++(Test&);
    friend const Test operator++(Test&,int);
public:
    int a;
};

Test& operator++(Test& val)//前遞增
{
    val.a++;
    return val;
}

const Test operator++(Test& val,int)//後遞增,int在這裏只起到區分作用,沒有實際意義
{
    Test temp(val);//這裏會調用拷貝構造函數進行對象的複製工作
    val.a++;
    return temp;
}


int main()
{
    Test test(5);
    ++++test;
    cout<<"test.a= "<<test.a<<endl;
    cout<<"後遞增情況下臨時存儲對象的值狀態:"<<(test++).a<<endl;
    cout<<"test.a= "<<test.a<<endl;

    Test test1(5);
    (test1++)++;
    cout<<"test1.a= "<<test1.a<<endl;
    cout<<"前遞增情況下臨時存儲對象的值狀態:"<<(++test1).a<<endl;
    cout<<"test1.a= "<<test1.a<<endl;

    
    return 0;
}
複製代碼

運行結果:

test.a= 7

後遞增情況下臨時存儲對象的值狀態:7

test.a= 8

test1.a= 6

前遞增情況下臨時存儲對象的值狀態:7

test1.a= 7

  上面代碼是非成員格式,在《C++編程慣用法—高級程序員常用方法和技巧》中講到對所有的一元操作符建議重載操作符函數爲成員函數

複製代碼
#include <iostream>
using namespace std;

class Test
{
public:
    Test(int a=0)
    {
        Test::a=a;
    }
    Test& operator++();
    const Test operator++(int);
public:
    int a;
};

Test& Test::operator++()//前遞增
{
    this->a++;
    return *this;
}

const Test Test::operator++(int)//後遞增,int在這裏只起到區分作用,沒有實際意義
{
    Test temp(*this);//這裏會調用拷貝構造函數進行對象的複製工作
    this->a++;
    return temp;
}


int main()
{
    Test test(5);
    ++++test;
    cout<<"test.a= "<<test.a<<endl;
    cout<<"後遞增情況下臨時存儲對象的值狀態:"<<(test++).a<<endl;
    cout<<"test.a= "<<test.a<<endl;

    Test test1(5);
    (test1++)++;
    cout<<"test1.a= "<<test1.a<<endl;
    cout<<"前遞增情況下臨時存儲對象的值狀態:"<<(++test1).a<<endl;
    cout<<"test1.a= "<<test1.a<<endl;

    
    return 0;
}
複製代碼

運行結果:

test.a= 7

後遞增情況下臨時存儲對象的值狀態:7

test.a= 8

test1.a= 6

前遞增情況下臨時存儲對象的值狀態:7

test1.a= 7

       在這裏注意一點:爲什麼(test1++)++能編譯通過,而上面提到的(a++)++卻不能編譯通過,這是因爲進行(test1++)後,假設臨時變量爲temp,則temp=test1(原來的test1值),然後進行temp++,其實是進行的是temp.a++,而temp成員a是一個變量,所以可以進行自增運算。

  這裏注意,紅色標誌的const是我後面加上去的,但加上去了,我上面的運行結果就會出錯了,因爲temp爲const對象了,後面自然不能自增++了,而且我認爲應該加const,避免(test1++)++這樣出現。

  最後再想下,

  Test& operator++();

  const Test operator++(int);
  爲什麼一個返回引用,一個要返回const。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章