首頁 > 軟體

詳解C++中賦值,關係,函數呼叫運運算元過載的實現

2022-06-13 14:03:48

賦值運運算元過載

在C++中基本資料型別例如整型,可以實現連續賦值:a=b=c;而我們的物件的成員屬性雖然可以相等,但是如果牽扯到堆地址,就會有深淺拷貝的問題存在。所以我們自己過載賦值運運算元,實現連等的方法。

類結構

class Info
{
    int* m_a;
public:
    Info()
    {
        m_a = NULL;
    }
    Info(int a)
    {
        m_a = new int(a);
    }
    ~Info()
    {
        if (m_a != NULL)
            delete m_a;
        m_a = NULL;
    }
    
};

建立一個Info類,定義指標屬性*m_a, 然後自己定義Info類的無參、有參建構函式和解構函式,再給屬性賦值的時候,是用new關鍵字開闢堆區並存放資料;解構在前面的文章中講到了他的作用,就是在程式結束前編譯器自動呼叫解構來完成物件的清理工作,在這裡就會把堆區的資料釋放掉。

問題的出現

Info f(20);
Info f1;
Info f2;
Info f3(30);
f1 = f2 =f;

直接連等是不行的,因為在解構函式裡存取了一個NULL地址,就比如程式即將結束,f呼叫解構函式,刪除m_a指向的地址,然而f1也會呼叫解構函式,由於f1和f的m_a指向同一個地址,那就好重複存取,存取一個被刪除的地址肯定會報錯的;因此我們需要對賦值運運算元進行過載,這裡提示一下,連等就相當於鏈式呼叫,因此過載運運算元的返回值型別需要返回參照。

具體實現

Info& operator=(Info& f)
    {
        if (m_a != NULL)
            delete m_a;
        m_a = NULL;
        m_a = new int(*f.m_a);
        return *this;
    }

返回值型別是類參照,這樣可以做到鏈式呼叫 ,函數名還是統一的operator+運運算元,既然是賦值運運算元就用operator=,然後這個過載發生在成員內部,因此引數裡只需要傳入用來賦值的物件即可,注意倒數第二行程式碼,我利用new讓m_a指向堆區中新開闢的地址,這是賦值運運算元過載的關鍵;就是因為把地址指向了堆區的新地址,這樣不同的物件在呼叫解構函式的時候各刪各的堆地址,不會存取空地址,這個問題的解決和深淺拷貝的解決方式一樣,都是自己寫方法來避免原來方法中成員屬性指向同一個地址。最後返回自身的參照,就可以實現連續呼叫了。

關係運算子過載

關係運算子有“大於”、“小於”、“等於”、“大於等於”、“不等於”等幾種情況,我就舉例等於和不等於兩種賦值運運算元過載的例子

類結構

class Info
{
    friend void test1();
    int* m_a;
    string m_name;
public:
    Info()
    {
        m_a = NULL;
    }
    Info(int a,string name)
    {
        m_a = new int(a);
        m_name = name;
    }
    ~Info()
    {
        if (m_a != NULL)
            delete m_a;
        m_a = NULL;
    }
}

這裡的類結構相比於賦值運運算元過載多了一個String型別的m_name屬性,然後寫出類的無參、有參構造和解構函式,最上面的friend關鍵字是加了一個友元的宣告,讓下面的test1函數可以存取類的私有屬性。

具體實現

    bool operator==(Info& f)
    {
        if (*this->m_a == *f.m_a && m_name==f.m_name)
            return true;
        else return false;
    }
    bool operator!=(Info& f)
    {
        if (*this->m_a == *f.m_a && m_name == f.m_name)
            return false;
        else return true;
    }

返回值型別寫成布林型別,因為關係運算的結果就是布林型別的,常和while迴圈以及if語句使用;函數名還是老樣子,operator==和operator!=,分別是相等和不等;既然是成員內部的關係運算子過載,那麼形參傳入一個待比較物件即可。

呼叫方法

void test1()
{
    Info f1(20,"張三");
    Info f3(30,"張六");
    if (f1== f3) cout << "二者相等" << endl;
    else if (f1!= f3) cout << "二者不相等" << endl;
}

執行效果 

函數呼叫運運算元過載

函數呼叫使用“()”,函數呼叫也是可以過載的,而且過載的呼叫很像直接呼叫函數,因此也叫做仿函數。

類結構

class MyHello
{
public:
    string hello;
};

非常簡單的類結構,只有一個公有許可權下的String型別的hello屬性。

具體實現

    void operator()(string s)
    {
        cout << s << endl;
    }

因為只是列印一下,不需要返回值,函數名不多說了,和前面類似,然後傳入字串型別再方法裡列印出來。

呼叫方法 

void test()
{
    MyHello hello;
    hello("Hello World");
}

首先建立類物件hello,直接使用過載後的呼叫方法:物件+(字串);這樣就能列印出引號裡的內容了:

匿名物件呼叫

最後補充一個匿名物件的知識,範例:

class MyAdd
{
public:
    int operator()(int num1, int num2)
    {
        return num1 + num2;
    }
};
void test1()
{
    MyAdd myAdd;
    int num = myAdd(160, 40);
    cout << "ret =" << myAdd(160,40) << endl;
    cout << "ret =" << MyAdd()(100,50) << endl;
}

這裡我寫了一個只有過載函數呼叫函數的類,並在test1中用常規和匿名物件呼叫過載後的函數呼叫方法;看一下執行效果:

先建立物件,再通過物件呼叫函數的方法我們不感到奇怪,但是最後一個輸出語句中,MyAdd()(100,50)是什麼意思呢 ,這就是匿名物件,往後我們遇到形如類名+()再+呼叫函數的方式,那就是建立了匿名物件,其特點就是建立完畢後就會刪除,這裡我們只都一下資料,所以適合匿名物件的呼叫。

總結

到這裡C++的運運算元過載徹底結束了,運運算元過載可以多個都過載並互相配合使用,把物件的屬性可以和基本型別一樣進行算數運算和邏輯運算,在類物件比較多的時候可以節省很多時間,簡化程式。

以上就是詳解C++中賦值,關係,函數呼叫運運算元過載的實現的詳細內容,更多關於C++運運算元過載的資料請關注it145.com其它相關文章!


IT145.com E-mail:sddin#qq.com