您的位置:首頁>正文

淺談重載操作符

前言

重載操作符可以成為強有力的工具, 但不可拋棄與客戶的契約而濫用, 那樣只會讓程式更難讓人理解。

——《c++物件導向高效程式設計》

背景

XXX:誒, 你快過來

博主:蛤蛤蛤?怎麼了?

XXX:你教教我那個星號, 不是, 乘號怎麼打啊

博主:乘號怎麼打是什麼意思啊 喵喵喵

XXX:就是可以讓這兩個矩陣乘起來啊

博主:。 。 。 你不會是在說重載吧

XXX:對啊= =

博主:等我給你寫完this, 就來寫重載

基本介紹&引入

照例引度娘:

操作符重載, 電腦科學概念, 就是把已經定義的、有一定功能的操作符進行重新定義, 來完成更為細緻具體的運算等功能。

操作符重載可以將概括性的抽象操作符具體化, 便於外部調用而無需知曉內部具體運算過程。

先舉個栗子例子:

int a,b,c;a=2333;b=666;c=a*b;

這段代碼的意思十分明顯, 就是聲明了兩個變數a和b, a賦值為2333, b賦值為666, c賦值為a*b, 即1553778。

重要的是, int類型是語言精妙的定義實現過的內置資料類型, 我們一寫a*b, 語言就會很好的計算出它正確的值(你要是爆了int當我沒說), 但是, 假如我們把int換個類型呢?語言還能否正確的計算出我們想要得到的結果呢?

我們打下這樣的代碼:

struct matrix{ int data[100][100];}a,b;int main{ matrix c; c=a*b;}

然後試著編譯一下, 就會出現:

顯然, 這樣是不行的, 那麼, 我們是否有辦法像使用int一樣使用我們自己定義的結構體matrix呢?

基本操作

我們繼續分析上面的編譯資訊, 顯然, 編譯器正在尋找一個叫'operator*'的東西,

這個東西是什麼呢?

顯然就是我們今天要講的主題——重載操作符。

operator, 關鍵字, 語法:

返回類型 operator 操作符 (參數列表){}

比如說, 上面我們想要實現的那個矩陣乘, 就可以像這樣子實現:

struct matrix{ int data[2][2]; matrix operator*(const matrix &a){ matrix tmp; for(int i=0;i<2;i++) for(int j=0;j<2;j++){ tmp.data[i][j]=0; for(int k=0;k<2;k++) tmp.data[i][j]+=data[i][k]*a.data[k][j]; }
return tmp;
} };

這樣我們再寫兩個matrix相乘, 就可以開心地通過編譯啦。

我們看到了乘號的重載, 那麼同樣的, 我們也可以重載加號, 減號, 設定運算子。 。 。

事實上, 除了 . .* :: ?: sizeof typeid 這幾個運算子不能被重載, 其他運算子都能被重載。

那麼, 有了*, 自然可以有*=, 而*=的實現完全可以依靠*的實現

matrix operator*=(const matrix &a){ *this=*this*a; return *this;}

其中, *this為調用該函數(重載操作符其實就是以操作符為函數名的函數)的物件, 更多有關this指標的用法可以參考我的上一篇博文

如何定義與使用

我們剛才已經見到了一種定義方法——將重載函式宣告為成員函數,

那麼, 還有其他定義重載的方法嗎?

當然有。

我們完全可以把運算子重載函式宣告為非成員函數, 而此時使用最多的是友元函數。

舉個栗子例子:

struct point{ double x,y; inline friend bool operator<(const point &a,const point &b){ return a.x==b.x?a.y顯然, 在這裡, 一個運算子重載函數被聲明為了(非成員)友元函數, 另一個則是非成員函數。

進階

現在, 我們已經可以進行簡單的重載了, 但是, 還有一些需要注意的特殊操作符

++

自加操作符

我們知道, 自加操作符有前置與後置兩種用法, 區別如下:

int a,b,c,d;a=2333;b=2333;c=a++;//運行完後, a為2334, c為2333d=++b;//運行完後, b和d都為2334

那麼顯然這兩種操作是不一樣的(令人窒息的操作)。 那麼如何進行這兩種重載呢?

前置:返回數值型別& operator++

後置:返回數值型別& operator++(int)

注意, 為了區分前置++與後置++的區別, 需要在參數後增加一個"int"以示區分。

含有"int"的重載方式為後置++, 否則為前置++。 前置--與後置--類似用法。

舉個栗子例子:

struct Int{ int data; Int& operator++;//前置 Int& operator++(int);//後置};

實現就可以根據自己需要進行了。

我們知道, 想輸入輸出一個int, 是十分簡單的事, 比如:

int a;cin>>a;a+=666;a*=2333;cout<但是, 假如我們寫下這個呢?

struct matrix{ blabla...}a;int main{ cout<顯然是不可以的, 所以我們需要重載。

這裡, 我們不是要重載matrix的什麼, 而是重載istream&ostream裡的某些東西。

我們知道, cin是輸入流物件, cout是輸出流物件, 所以我們要重載的物件是cin的>>與cout的<<

以matrix(矩陣)為例, 我一般的寫法是:

struct matrix{ int data[100][100];};istream& operator>>(istream &in,matrix &x){ for(int i=0;i<100;i++) for(int j=0;j<100;j++) in>>x.data[i][j]; return in;}ostream& operator<<(ostream &out,matrix &x){ for(int i=0;i<100;i++){ for(int j=0;j<100;j++) out<這樣就很健康啦

WARNING

有約定需要注意:

流物件不允許複製, 所以只能返回引用

原理

事實上, 我們在寫

struct Int{
blabla...
}
Int a,b,c; a=2333; b=666; c=a+b;

實際上是調用了

c=a.operator+(b);

我們完全可以把它看做一個函數, 不過是函數名有些特殊罷了。

原則 並不是所有的操作符都能被重載。 除了. , .* , :: , ? : , sizeof, typeid這幾個運算子不能被重載,
其他運算子都能被重載重載不能改變該運算子用於內置類型時的函義, 程式師不能改變運算子+用於兩個int型時的含義。 運算子函數的參數至少有一個必須是類的物件或者類的物件的引用。 這種規定可以防止程式師運用運算子改變內置類型的函義。 重載不能改變運算子的優先順序。 重載不能改變運算子的結合律。 重載不能改變運算子運算元的個數。 比如+需要兩個運算元, 則重載的+也必須要有兩個運算元。

還有一個很重要的原則

不可改變操作符固有的含義, 要保留與客戶之間約定的契約, 如果你將+重載為減法或是乘法, 這會使你的程式更加令人費解

總結

重載操作符是一個強大的工具, 運用好重載,可以使你的代碼更簡潔,明白。

運用好重載,可以使你的代碼更簡潔,明白。

同類文章
Next Article
喜欢就按个赞吧!!!
点击关闭提示