在一些情況下,會想將兩個物件進行 +
、-
、*
、/
運算,例如在定義了有理數類別之後,若能透過 +
、-
、*
、/
之類的運算來處理,程式碼撰寫上會比較直覺,在 C++ 中,可以透過重載運算子來達到目的。
運算子重載是函式重載的延伸應用,定義類別時可以指定重載哪個運算子,實作對應的運算,運算子重載的語法如下:
傳回型態 類別名稱::operator#(參數列) {
// 實作重載內容
}
其中 #
指明要重載哪個運算子,例如重載一個 +
運算子,#
處就替換為 +
。
如果要重載 ++
或 --
運算子,必須注意前置與後置,這是使用一個 int 參數來區別:
傳回型態 operator++(); // 前置,例如 ++x
傳回型態 operator++(int); // 後置,例如 x++
傳回型態 operator--(); // 前置,例如 --x
傳回型態 operator--(int); // 後置,例如 x--
後置的 int
會傳入 0,實際上沒有作用,只是用來識別前置或後置,通常在重載 ++
與 --
運算子時,前置與後置都要重載。
底下範例定義了有理數 Rational
類別,並重載了一些運算子:
#include <iostream>
#include <string>
using namespace std;
class Rational {
int numer;
int denom;
public:
Rational(int numer, int denom) : numer(numer), denom(denom) {}
Rational operator+(const Rational&);
Rational operator-(const Rational&);
Rational operator*(const Rational&);
Rational operator/(const Rational&);
Rational& operator++();
Rational& operator--();
Rational operator++(int);
Rational operator--(int);
string to_string() const;
};
Rational Rational::operator+(const Rational &that) {
return Rational(
this->numer * that.denom + that.numer * this->denom,
this->denom * that.denom
);
}
Rational Rational::operator-(const Rational &that) {
return Rational(
this->numer * that.denom - that.numer * this->denom,
this->denom * that.denom
);
}
Rational Rational::operator*(const Rational &that) {
return Rational(
this->numer * that.numer,
this->denom * that.denom
);
}
Rational Rational::operator/(const Rational &that) {
return Rational(
this->numer * that.denom,
this->denom * that.numer
);
}
Rational& Rational::operator++() {
this->numer = this->numer + this->denom;
return (*this);
}
Rational& Rational::operator--() {
this->numer = this->numer - this->denom;
return (*this);
}
Rational Rational::operator++(int) {
Rational r = (*this);
this->numer = this->numer + this->denom;
return r;
}
Rational Rational::operator--(int) {
Rational r = (*this);
this->numer = this->numer - this->denom;
return r;
}
string Rational::to_string() const {
return std::to_string(this->numer) + "/" + std::to_string(this->denom);
}
int main() {
Rational a(1, 2);
Rational b(2, 3);
cout << (a + b).to_string() << endl;
cout << (a - b).to_string() << endl;
cout << (a * b).to_string() << endl;
cout << (a / b).to_string() << endl;
cout << (++a).to_string() << endl;
cout << (--a).to_string() << endl;
cout << (b++).to_string() << endl;
cout << (b--).to_string() << endl;
return 0;
}
有些運算子重載可以實作為類別成員函式,也可以實作為一般函式,涉及 private
值域存取的,通常會實作為成員函式,然而,若運算子涉及不同型態的運算,例如 Rational
加法運算的左或右運算元,可以是 int
整數的話,運算子就得定義為非成員函式,例如:
#include <iostream>
#include <string>
using namespace std;
class Rational {
int numer;
int denom;
public:
Rational(int numer, int denom) : numer(numer), denom(denom) {}
friend Rational operator+(int, const Rational&);
friend Rational operator+(const Rational&, int);
...略
};
...略
Rational operator+(int lhs, const Rational &rhs) {
return Rational(
lhs * rhs.denom + rhs.numer,
rhs.denom
);
}
Rational operator+(const Rational &lhs, int rhs) {
return Rational(
lhs.numer + rhs * lhs.denom,
lhs.denom
);
}
...略
int main() {
Rational a(1, 2);
Rational b(2, 3);
...略
cout << (1 + a).to_string() << endl;
cout << (a + 1).to_string() << endl;
return 0;
}
有時候,你不能或不想修改物件的類別原始碼,例如,想重載 cout
的 <<
運算子,這時就只能選擇實作為非成員函式:
#include <iostream>
#include <string>
using namespace std;
class Rational {
...略
public:
...略
string to_string() const;
};
...略
string Rational::to_string() const {
return std::to_string(this->numer) + "/" + std::to_string(this->denom);
}
ostream& operator<<(ostream &os, const Rational &r) {
return os << r.to_string();
}
int main() {
Rational a(1, 2);
Rational b(2, 3);
cout << (a + b) << endl;
cout << (a - b) << endl;
cout << (a * b) << endl;
cout << (a / b) << endl;
cout << (++a) << endl;
cout << (--a) << endl;
cout << (b++) << endl;
cout << (b--) << endl;
cout << (1 + a) << endl;
cout << (a + 1) << endl;
return 0;
}
大部份的運算子都是可以被重載的,然而 .
、::
、.*
、?:
不能重載。