运算符重载例题

用的是vs2019编译器

这是一个有关运算符重载的例题,希望大家作以参考

定义有理数类(分母不为0的分数,分子分母均为整数)Rational,实现相应操作符的重载。
(1)定义私有数据成员分子int iUp ; 分母int iDown
(2)定义私有成员函数void Reduce()int Gcd(int l, int r),分别用于有理数的约简求两个整数的最大公约数。其中,在约简时需要求取分子与分母的最大公约数。
(3)定义构造函数,在构造函数体内可调用Reduce对有理数进行约简。
(4)将负号-和赋值运算符=重载为公有成员函数,分别用于求有理数的负数和赋值。
(5)将前置++、前置–、后置++、后置–重载为公有成员函数,实现有理数自增1或自减1。
(6)将+、-、*、/重载为友员函数,实现有理数的加减乘除。
(7)将<、<=、>、>=重载为友员函数,实现有理数的大小关系比较。
(8)重载流插入符<<和流提取符>>,分别用于有理数的输出和输入。其中,输出格式为“分子/分母”,若为整数,则直接输出整数。
在main函数中,根据输入的分子和分母定义两个有理数对象a和b。再定义几个有理数对象分别用于表示a和b的加、减、乘、除、前置自增a、前置自减a、后置自增a、后置自减a,并依次各个对象的结果。最后依次用<、<=、>、>=比较a和b的大小关系,并依次输出比较结果(true或false)。

输入

两个有理数a和b的的分子和分母

输出

有理数a和b的加、减、乘、除以及前置自增a、前置自减a、后置自增a、后置自减a有理数a和b的<、<=、>、>=的结果

样例输入

4 3
3 2

样例输出

a+b: 17/6
a-b: -1/6
a*b: 2
a/b: 8/9
-a: -4/3
++a: 7/3
–a: 4/3
a++: 4/3
a–: 7/3
a<b: true
a<=b: true
a>b: false
a>=b: false

下面展示此题代码

#include <iostream>
using namespace std;

class Rational{
    friend Rational operator+(Rational& p1, Rational& p2);
    friend Rational operator-(Rational& p1, Rational& p2);
    friend Rational operator*(Rational& p1, Rational& p2);
    friend Rational operator/(Rational& p1, Rational& p2);
    friend bool operator<(Rational& p1, Rational& p2);
    friend bool operator<=(Rational& p1, Rational& p2);
    friend bool operator>(Rational& p1, Rational& p2);
    friend bool operator>=(Rational& p1, Rational& p2);
    friend ostream& operator <<(ostream& cout, Rational& p);
    friend istream& operator >>(istream& cin, Rational& p);
private:
    int iUp;
    int iDown;
    
    //有理数约简
    void Reduce() {
        int t = abs(Gcd(iUp, iDown));
        iUp = iUp / t;
        iDown = iDown / t;
        if (iDown < 0){
            iDown = -iDown; 
            iUp = -iUp; 
        }
    }

    int Gcd(int l, int r) {
        int temp = l % r;
        while (temp != 0) {
            l = r;
            r = temp;
            temp = l % r;
        }

        return r;
    }
    
public:
    Rational() {
        iUp = 1;
        iDown = 1;
    }
    Rational(int a,int b) {
        iUp = a;
        iDown = b;
        Reduce();
    }
	//相反数
    Rational operator-()  { 
        Rational temp;
        temp.iUp = -iUp;
        temp.iDown = iDown;
        return temp;
    }
	//赋值    
    Rational& operator=(const Rational& p) {
        iUp = p.iUp;
        iDown = p.iDown;
        Reduce();
        return *this;
    }
    //前置++
    Rational& operator++() {
        iUp += iDown;
        Reduce();
        return *this;
    }
    //前置--
    Rational& operator--() {
        iUp -= iDown;
        return *this;
    }
    //后置++
    Rational operator++(int) {
        Rational temp = *this;
        iUp += iDown;
        return temp;
    }
    //后置--
    Rational operator--(int) {
        Rational temp = *this;
        iUp -= iDown;
        return temp;
    }  
   
};
//加法+
Rational operator+(Rational& p1, Rational& p2) {
    Rational temp;
    temp.iDown = p1.iDown * p2.iDown;
    temp.iUp = p1.iUp * p2.iDown + p2.iUp * p1.iDown;
    temp.Reduce();
    return temp;
}
//减法-
Rational operator-(Rational& p1, Rational& p2) {
    Rational temp;
    temp.iDown = p1.iDown * p2.iDown;
    temp.iUp = p1.iUp * p2.iDown - p2.iUp * p1.iDown;
    temp.Reduce();
    return temp;
}
//乘法*
Rational operator*(Rational& p1, Rational& p2) {
    Rational temp;
    temp.iUp = p1.iUp * p2.iUp;
    temp.iDown = p1.iDown * p2.iDown;
    temp.Reduce();
    return temp;
}
//除法/
Rational operator/(Rational& p1, Rational& p2) {
    Rational temp;
    temp.iUp = p1.iUp * p2.iDown;
    temp.iDown = p1.iDown * p2.iUp;
    temp.Reduce();
    return temp;
}
//<号
bool operator<(Rational& p1, Rational& p2) {
    int temp;
    temp = p1.iDown * p2.iDown;
    p1.iDown = temp;
    p1.iUp += p2.iDown;
    p2.iDown = temp;
    p2.iUp += p1.iDown;
    p1.Reduce();
    p2.Reduce();
    if (p1.iUp < p2.iUp) {
        return true;
    }
    return false;
}
bool operator<=(Rational& p1, Rational& p2) {
    int temp;
    temp = p1.iDown * p2.iDown;
    p1.iDown = temp;
    p1.iUp += p2.iDown;
    p2.iDown = temp;
    p2.iUp += p1.iDown;
    p1.Reduce();
    p2.Reduce();
    if (p1.iUp <= p2.iUp) {
        return true;
    }
    return false;
}
bool operator>(Rational& p1, Rational& p2) {
    int temp;
    temp = p1.iDown * p2.iDown;
    p1.iDown = temp;
    p1.iUp += p2.iDown;
    p2.iDown = temp;
    p2.iUp += p1.iDown;
    p1.Reduce();
    p2.Reduce();
    if (p1.iUp > p2.iUp) {
        return true;
    }
    return false;
}
bool operator>=(Rational& p1, Rational& p2) {
    int temp;
    temp = p1.iDown * p2.iDown;
    p1.iDown = temp;
    p1.iUp += p2.iDown;
    p2.iDown = temp;
    p2.iUp += p1.iDown;
    p1.Reduce();
    p2.Reduce();
    if (p1.iUp >= p2.iUp) {
        return true;
    }
    return false;
}
ostream& operator <<(ostream& cout, Rational& p) {
    int temp;
    if (p.iUp % p.iDown == 0) {
        cout << p.iUp / p.iDown <<endl;
    }else {
        cout << p.iUp << "/" << p.iDown << endl;
    }
    return cout;
}
istream& operator >>(istream& cin, Rational& p) {
    cin >> p.iUp >> p.iDown;
    //cout << p.iUp << "/" << p.iDown << endl;
    return cin;
}


int main()
{
    Rational a;
    Rational b;
    cin >> a;
    cin >> b;
    Rational c;				
    c = a + b;
    cout << "a+b: " << c ;
    c = a - b;
    cout << "a-b: " << c;
    c = a * b;
    cout << "a*b: " << c;
    c = a / b;
    cout << "a/b: " << c;
    c = -a;
    cout << "-a: " << c ;
    cout << "++a: " << ++a ;
    cout << "--a: " << --a ;
    c = a++;
    cout << "a++: " << c ;
    c = a--;
    cout << "a--: " << c ;
    bool d;
    d = (a < b);
    cout << "a<b: " << boolalpha << d << endl;
    d = (a <= b);
    cout << "a<=b: " << boolalpha << d<< endl;
    d = (a > b);
    cout << "a>b: " << boolalpha << d << endl;
    d = (a >= b);
    cout << "a>=b: " << boolalpha << d << endl;
    system("pause");
}




对于这个题本人遇到的一些小问题

  1. 为什么在最后输出的时候引入了新的值cd
    因为在重载<<和>>时,传入的是一个类对象的引用。例如,若直接写成
    cout<<"a+b: "<< a + b << endl ;则会造成重载的其实是a + b这两个类对象的重载的加运算。

  2. 对于返回类类型的运算符重载来说,为什么有的返回的是类类型的引用?
    以上代码在进行加减乘除时,都在重载函数内用了临时的类类型变量temp,所以如果用返回引用的话,编译器会报错,因为temp的生命周期只是在函数内,无法传它的引用到外界。而在前置++赋值=前置– 中,返回的是传入值的本身,所以要用引用返回。

  3. 关于void Reduce()函数在每一个二元运算中的调用。
    调用的原因其实很简单,但是会很容易忽视。因为在二元运算后,可能会改变分子分母的符号,所以必须调用此函数,来调整输出,以保证如果是负数,输出时负号是在分子前面的,也可以调用此函数进行上下都是负数,从而约简成都是正数。