c++運算符重載


1.說明

  [1]重載運算符函數的參數個數,應該與參與這個運算符的運算對象數量一樣多,但是如果是成員函數,則參數數量要少一個,因為第一個參數是this。例如:

#include <stdio.h>
#include <stdlib.h>

using namespace std;

class ca
{
public:    
    int value;
    //重載為成員函數格式
    int operator+(const ca &v){
        return this->value + v.value; // 等同於return value+v.value;
    }
};

//重載為非成員函數格式
int operator+(const ca &v1, const ca &v2)
{
    return v1.value + v2.value;
}

int main()
{
    ca a, b;

    a.value = 10;
    b.value = 20;

    printf("a+b:%d\n", a + b);    // 優先用成員函數
    
    return 0;
}

  [2]運算符重載函數的參數至少要有一個類的成員(或者類類型)作為參數,而不能都是內置類型(會導致編譯錯誤)。例如int operator+(int, int)是不行的,因為int是內置類型。內置類型的操作符明顯是不能重載的,比如重載了int型的+運算符,那程序其他地方的int加法都會使用重載的函數,這明顯是不行的。

  [3]運算符可以像普通函數一樣調用。例如上面例子的a+b等同於a.operator+(b);。

  [4]不應該重載的運算符(當然理論是可以重載的,只是重載之后容易出問題):逗號、&、&&、||。

  [5]必須作為成員函數的重載運算符:=、[]、()、->,否則會編譯錯誤。

  [6]重載運算符函數是成員函數時,其實就是運算符左側的對象調用的這個運算符,所以左側對象必須是運算符所屬類的一個對象(這個是當然的,因為第一個參數是這個類的this指針)。

2.輸入輸出運算符重載

  [1]首先“<<”和“>>”表示移位操作,然后IO標准庫(iostream庫)重載了這兩個運算符來處理輸入和輸出,自己重載這兩個運算符的目的就是要輸出自定義的類。

  [2]如果要與iostream庫兼容輸入輸出操作,則自己重載的時候必須作為非成員函數,這個是因為如果作為成員函數,則左側的操作對象應該是這個類的對象,這樣就不能兼容iostream庫的輸入輸出操作。當然非要重載為成員函數,也是可以編譯通過的,只不過是不能兼容標准庫iostream的輸入輸出操作而已。例如:

#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <iostream>

using namespace std;

class ca
{
public:    
    int value;

    //重載<<的目的就是要輸出類ca
    ca & operator<<(const ca &v){
        cout << "value:" << v.value << "\n";
        return *this;
    }
};

int main()
{
    ca a, b, c;
    
    a.value = 1;
    b.value = 2;
    c.value = 3;

    //重載函數作為成員函數之后,以后只能這樣調用。
    //顯然類ca的對象的輸出已經和正常的輸出不能兼容使用了。
    a << a;
    b << a;
    c << b << a;

    //例如下面這些都是不兼容的,不能編譯通過的。
    (cout << "ca info :") << a;
    a << b << "hello.\n";
    return 0;
}

  [3]因為IO運算符通常要訪問類的所有成員,正確的做法是把重載的非成員函數聲明為類的友元函數。

3.遞增和遞減運算符重載

  [1]遞增和遞減一般是改變對象的狀態,所以一般是重載為成員函數。

  [2]重載遞增遞減,一定要和指針的遞增遞減區分開。因為這里的重載操作的是對象,而不是指針(由於指針是內置類型,指針的遞增遞減是無法重載的),所以一般情況的遞增遞減是操作對象內部的成員變量。

  [3]遞增和遞減分為前置和后置情況,a = ++b;(前置), a = b++;(后置)。因為符號一樣,所以給后置版本加一個int形參作為區分,這個形參是0,但是在函數體中是用不到的,只是為了區分前置后置。例如:

#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <iostream>

using namespace std;

// 例如這里的重載遞增就是為了增加pos的值
class ca
{
public:    
    int pos;

    //前置遞增就是增加當前對象的pos的值,並且返回當前對象
    ca operator++(){
        pos++;
        return *this;
    }

    //后置遞增就是增加當前對象的pos的值,並且返回增加pos之前的該對象
    ca operator++(int){
        ca ret = *this;
        ++*this;        //這個會調用上面的函數,其實這里可以換成pos++;
        return ret;
    }
};

int main()
{
    ca a, b;

    a.pos = 1;

    b = a++;
    cout << "b1:" << b.pos << endl;   // b1:1
    
    b = ++a;
    cout << "b2:" << b.pos << endl;   // b1:3
    
    return 0;
}

 4.重載函數調用運算符“()”

  [1]類重載了括號運算符,則該類的對象就可以當成函數一樣來使用。另外類里面可以定義數據成員,這樣就比普通函數多了一些功能,例如保存一些狀態,統計該對象的調用次數等等。

  [2]這種對象常常用作泛型算法的實參,因為有些泛型算法可以提供自定義的比較函數。例如:

#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <vector>
#include <iostream>
#include <algorithm>

using namespace std;

void myprint(const string & s)
{
    printf("my print : %s\n", s.c_str());
    return ;
}

class ca
{
public:
    int call_times;
    ca(){call_times = 0;}
    
    void operator()(const string & s){
        printf("ca print : %s\n", s.c_str());
        call_times++;
    }
};

int main()
{
    vector<string> vs;

    vs.push_back("abc");
    vs.push_back("def");

    //普通函數也是可以代替仿函數的,只是功能不如仿函數強大
    for_each(vs.begin(), vs.end(), myprint);

    ca a;
    for_each(vs.begin(), vs.end(), a);                   //這里要注意,這個是值傳遞,傳的是a的副本
    printf("ca print call times: %d\n", a.call_times);   //所以這個地方的a.call_times還是0

    a("haha");
    a("hehe");
    printf("ca print call times: %d\n", a.call_times);   //現在a.call_times的值就是2了
    
    return 0;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM