运算符重载


在一些情况下,会想将两个对象进行+-*/运算,例如在定义了有理数类之后,若能透过+-*/之类的运算来处理,代码编写上会比较直觉,在 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;
}

大部份的运算符都是可以被重载的,然而.::.*?:不能重载。


展开阅读全文