c++運算符重載

1.說明ios

  [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);。this

  [4]不該該重載的運算符(固然理論是能夠重載的,只是重載以後容易出問題):逗號、&、&&、||。spa

  [5]必須做爲成員函數的重載運算符:=、[]、()、->,不然會編譯錯誤。指針

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

2.輸入輸出運算符重載對象

  [1]首先「<<」和「>>」表示移位操做,而後IO標準庫(iostream庫)重載了這兩個運算符來處理輸入和輸出,本身重載這兩個運算符的目的就是要輸出自定義的類。blog

  [2]若是要與iostream庫兼容輸入輸出操做,則本身重載的時候必須做爲非成員函數,這個是由於若是做爲成員函數,則左側的操做對象應該是這個類的對象,這樣就不能兼容iostream庫的輸入輸出操做。固然非要重載爲成員函數,也是能夠編譯經過的,只不過是不能兼容標準庫iostream的輸入輸出操做而已。例如:string

#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;
}
相關文章
相關標籤/搜索