电竞比分网-中国电竞赛事及体育赛事平台

分享

運算符重載 之返回類型、參數(shù)與引用疑問解答

 @IT小小鳥@ 2012-03-06
在c++中要想實現(xiàn)這樣的運算就必須自定義運算符重載函數(shù),讓它來完整具體工作。

  在這里要提醒讀者的是,自定義類的運算符重載函數(shù)也是函數(shù),你重載的一切運算符不會因為是你自己定義的就改變其運算的優(yōu)先級,自定義運算符的運算優(yōu)先級同樣遵循與內(nèi)部運算符一樣的順序。

  除此之外,c++也規(guī)定了一些運算符不能夠自定義重載,例如.、::、.*、.->、?:。

  下面我們來學(xué)習(xí)如何重載運算符,運算符重載函數(shù)的形式是:

返回類型 operator 運算符符號 (參數(shù)說明)
{
//函數(shù)體的內(nèi)部實現(xiàn)
}

  運算符重載函數(shù)的使用主要分為兩種形式,一種是作為類的友元函數(shù)進(jìn)行使用另一種則是作為類的成員函數(shù)進(jìn)行使用。

  下面我們先看一下作為類的友元函數(shù)使用的例子:

//程序作者:管寧     
//站點:www.cndev-lab.com     
//所有稿件均有版權(quán),如要轉(zhuǎn)載,請務(wù)必著名出處和作者    

#include <iostream>
using namespace std;

class Test
{
    public:
         Test(int a = 0)
         {
             Test::a = a;
         }
        friend Test operator +(Test&,Test&);
        friend Test& operator ++(Test&);
    public:
        int a;
};
Test operator +(Test& temp1,Test& temp2)//+運算符重載函數(shù)
{
    //cout<<temp1.a<<"|"<<temp2.a<<endl;//在這里可以觀察傳遞過來的引用對象的成員分量
     Test result(temp1.a+temp2.a);
    return result;
}
Test& operator ++(Test& temp)//++運算符重載函數(shù)
{
     temp.a++;
    return temp;
}
int main()
{
     Test a(100);
     Test c=a+a;
    cout<<c.a<<endl;
     c++;
    cout<<c.a<<endl;
     system("pause");
}

  在例子中,我們對于自定義類Test來說,重載了加運算符與自動遞增運算符,重載的運算符完成了同類型對象的加運算和遞增運算過程。

重載運算符函數(shù)返回類型和形式參數(shù)也是根據(jù)需要量進(jìn)行調(diào)整的,下面我們來看一下修改后的加運算符重載函數(shù)。

  代碼如下:

//程序作者:管寧     
//站點:www.cndev-lab.com     
//所有稿件均有版權(quán),如要轉(zhuǎn)載,請務(wù)必著名出處和作者    

#include <iostream>
using namespace std;

class Test
{
    public:
         Test(int a = 0)
         {
             Test::a = a;
         }
        friend Test operator +(Test&,const int&);
    public:
        int a;
};
Test operator +(Test& temp1,const int& temp2)//+運算符重載函數(shù)
{
     Test result(temp1.a * temp2);
    return result;
}
int main()
{
     Test a(100);
     Test c = a + 10;
    cout<<c.a<<endl;
     system("pause");
}

  上面修改后的例子中,我們讓重載后的加運算符做的事情,事實上并不是同類型對象的加運算,而是自定義類對象與內(nèi)置int常量對象的乘法運算。

  值得注意的是,對于運算符重載來說,我們并不一定要用它一定要做同類型對象的加法或者是其它運算,運算符重載函數(shù)本身就是函數(shù),那么在函數(shù)體內(nèi)部我們是可以做任何事情的,但是從不違背常規(guī)思維的角度來說,我們沒有必要讓重載加運算的函數(shù)來做與其重載的符號意義上完全不相符的工作,所以在使用重載運算符脫離原意之前,必須保證有足夠的理由。

  下面我們討論一下作為類成員函數(shù)的運算符重載函數(shù)的使用,及其函數(shù)的值返回與引用返回的差別。

  下面我們先看實例,而后逐步分析。

  代碼如下(重要部分做了詳細(xì)的注解):

//程序作者:管寧     
//站點:www.cndev-lab.com     
//所有稿件均有版權(quán),如要轉(zhuǎn)載,請務(wù)必著名出處和作者    

#include <iostream>
using namespace std;

class Test
{
    public:
         Test(int a = 0)
         {
             Test::a = a;
         }
         Test(Test &temp)
        //運算符重載函數(shù)為值返回的時候會產(chǎn)生臨時變量,臨時變量與局部變量result的復(fù)制會調(diào)用拷貝構(gòu)造函數(shù),臨時變量的生命周期是在拷貝構(gòu)造函數(shù)運行完成后才結(jié)束,但如果運算符重載函數(shù)返回的是引用,那么不會產(chǎn)生臨時變量,而局部變量result的生命周期在運算符重載函數(shù)退出后立即消失,它的生命周期要比臨時變量短,所以當(dāng)外部對象獲取返回值的內(nèi)存地址所存儲的值的時候,獲得是一個已經(jīng)失去效果的內(nèi)存地址中的值,在這里的值返回與引用返回的對比,證明了臨時變量的生命周期比局部變量的生命周期稍長。
         {
            cout<<"載入拷貝構(gòu)造函數(shù)"<<"|"<<temp.a<<endl;//注意這里,如果修改運算符重載函數(shù)為返回引用,這里就會出現(xiàn)異常,temp.a將獲得一個隨機值。
             Test::a = temp.a;
         }
         ~Test()//在mian()內(nèi)析構(gòu)的過程是result局部變量產(chǎn)生的
         {
            cout<<"載入析構(gòu)函數(shù)!"<<endl;
            cin.get();
         }
         Test operator +(Test& temp2)//+運算符重載函數(shù)
         {
            //cout<<this->a<<endl;
             Test result(this->a+temp2.a);
            return result;
         }
         Test& operator ++()//++運算符重載函數(shù)

        //遞增運算符是單目運算符,使用返回引用的運算符重載函數(shù)道理就在于它需要改變自身。
        //在前面我們學(xué)習(xí)引用的單元中我們知道,返回引用的函數(shù)是可以作為左值參與運算的,這一點也符合單目運算符的特點。
        //如果把該函數(shù)改成返回值,而不是返回引用的話就破壞了單目預(yù)算改變自身的特點,程序中的++(++c)運算結(jié)束后輸出c.a,會發(fā)現(xiàn)對象c只做了一次遞增運算,原因在于,當(dāng)函數(shù)是值返回狀態(tài)的時候括號內(nèi)的++c返回的不是c本身而是臨時變量,用臨時變量參與括號外的++運算,當(dāng)然c的值也就只改變了一次。
         {
            this->a++;
            return *this;
         }
    public:
        int a;
};

int main()
{
     Test a(100);
     Test c=a+a;
    cout<<c.a<<endl;
     c++;
    cout<<c.a<<endl;
     ++c;
    cout<<c.a<<endl;
     ++(++c);
    cout<<c.a<<endl;
     system("pause");
}

  上例中運算符重載函數(shù)以類的成員函數(shù)方式出現(xiàn),細(xì)心的讀者會發(fā)現(xiàn)加運算和遞增運算重載函數(shù)少了一個參數(shù),這是為什么呢?
  因為當(dāng)運算符重載函數(shù)以類成員函數(shù)身份出現(xiàn)的時候,C++會隱藏第一個參數(shù),轉(zhuǎn)而取代的是一個this指針。

接下來我們具體分析一下運算符重載函數(shù)的值返回與引用返回的差別

  當(dāng)我們把代碼中的加運算重載函數(shù)修改成返回引用的時候:

         Test& operator +(Test& temp2)//+運算符重載函數(shù)   
         {
             Test result(this->a+temp2.a);   
            return result;   
         }

  執(zhí)行運算符重載函數(shù)返回引用將不產(chǎn)生臨時變量,外部的Test c=a+a; 將獲得一個局部的,棧空間內(nèi)存地址位置上的值,而??臻g的特性告訴我們,當(dāng)函數(shù)退出的時候函數(shù)體中局部對象的生命周期隨之結(jié)束,所以保存在該地址中的數(shù)據(jù)也將消失,當(dāng)c對象去獲取存儲在這個地址中的值的時候,里面的數(shù)據(jù)已經(jīng)不存在,導(dǎo)致c獲得的是一個隨機值,所以作為雙目運算的加運算符重載函數(shù)是不益采用返回引用方式編寫的,當(dāng)然如果一定要返回引用,我們可以在堆內(nèi)存中動態(tài)開辟空間存儲數(shù)據(jù),但是這么做會導(dǎo)致額外的系統(tǒng)開銷,同時也會讓程序更難讀懂。


  對于遞增運算符來說,它的意義在于能夠改變自身,返回引用的函數(shù)是可以作為左值參與運算的,所以作為單目運算符,重載它的函數(shù)采用返回引用的方式編寫是最合適的。

  如果我們修改遞增運算符重載函數(shù)為值返回狀態(tài)的時候,又會出現(xiàn)什么奇怪的現(xiàn)象呢?

  代碼如下:

         Test operator ++()
         {
            return this->a++;
         }

  表面上是發(fā)現(xiàn)不出什么特別明顯的問題的,但是在main()函數(shù)中++(++c);的執(zhí)行結(jié)果卻出乎意料,理論上應(yīng)該是204的值,卻只是203,這是為什么呢?

  因為當(dāng)函數(shù)是值返回狀態(tài)的時候括號內(nèi)的++c返回的不是c本身而是臨時變量,用臨時變量參與括號外的++運算,當(dāng)然c的值也就只改變了一次。結(jié)果為203而不是204。

  對于運算符重載函數(shù)來說,最后我們還要注意一個問題,當(dāng)運算符重載函數(shù)的形式參數(shù)類型全部為內(nèi)部類型的時候,將不能重載。

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多