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; }
