Перегрузка оператора. Сложение дробей

155
26 сентября 2019, 18:50

Изменяю код, в расчёте, может быть кому-нибудь пригодится. Задача: Даны две дроби a/b и c/d.

Создайте класс Fraction, который будет хранить дробь вида x/y. На вход: 2/3 4/5 Ответ: 22/15

PS Задачи сократить дробь нет. Надо только ввести две обыкновенные дроби с клавиатуры, сложить их и вывести ответ в виде также обыкновенной дроби. Цель продемонстрировать перегрузку операторов.

#include <iostream>
#include <cstring>
using namespace std;
typedef long long int ll_int;
class Fraction{
    ll_int x, y;
public:
    Fraction(ll_int x = 0, ll_int y =1): x(x),y(y){}
    void read();      // Ввод обыкновенных дробей с клавиатуры                
    void show();      // Вывод результата суммы дробей.        
    Fraction operator +(Fraction &);   //Перегрузка оператора +
};
void Fraction::read(){
    char s;
    cin >> x >> s >> y;     //х  - числитель, s - "/", у - знаменатель   
}
void Fraction::show(){
    cout << x << "/" << y;           //х  - числитель, "/", у - знаменатель
}
Fraction Fraction::operator +(Fraction &v){        
    x = x * v.y + v.x * y;   //Сложение числителей первого и второго числа
    y = y * v.y;
    return *this;
}
int main(){
    Fraction a, b, c;
    a.read();
    b.read();
    c = a + b;
    c.show();
    return 0;
}
Answer 1

У вас уже есть замечания в комментариях. Вот мои:

  1. Функции read и show полностью специализированы на консоль. В общем случаи, правильнее, если они будут получать в аргумент обьект потока. read(std::istream&) и show(std::ostream&). Также, можно вместо этого определять операторы >> и <<.
  2. Вы совсем не пытаетесь сокращать дробь, а это логичный ход для этого класса.
  3. Методы, которые не модифицируют обьект и могут не иметь доступ к закрытым и защищенным членам и не являются друзьями класса, лучше определять вне класса. Например, ваш класс может иметь operator *=, а operator * можете определить (с его помощью) вне класса.
  4. Вы неправильно определяете операторы. Например, как нужно умножить две дроби на бумаге, думаю знаете, но что вы написали в операторе умножения, не понятно...

Вы хотите(в программе) дробь умножить(сложить) на дробь, а не на число. Поэтому:

typedef long long int ll_int;
class Fraction{
    ll_int x, y;
public:
    Fraction(ll_int x = 0, ll_int y =1): x(x),y(y){}
    void read();      // Ввод обыкновенных дробей с клавиатуры
    Fraction& operator *=(const Fraction&);
    Fraction& operator +=(const Fraction&);
    void show() const;
};
void Fraction::read()
{
    using std::cin;
    cin >> x;        //пытаемся вводить числитель
    if (cin) {      //если ввод был нормальным, продолжаем
        if (cin.peek() == '/') {  //если следующий символ...
            cin.ignore();         // пропускаем
            cin >> y;
        }
        else     // если нет  символа '/'
            y = 1;
    }
}
// *= и += стоит реализовать для удобства использования класса
Fraction& Fraction::operator *=(const Fraction& f)
{
    x *= f.x;
    y *= f.y;
    return *this;
}
Fraction& Fraction::operator +=(const Fraction& f)
{
    x = x * f.y + y * f.x;
    y *= f.y;
    return *this;
}
void Fraction::show()  const
{
    cout << x << "/" << y;
}
// и вне класса уже можем определять + и *
Fraction operator *(Fraction& f1, const Fraction& f2)
{ return f1 *= f2; }
Fraction operator +(Fraction& f1, const Fraction& f2)
{ return f1 += f2; }
main()
{    
    Fraction a, b, c;
    a.read();
    b.read();
    c = a + b;
    c.show();
     cout << endl;
   // Так как оператор *= возвращает ссыльку на этот обьект
   // можем сразу выполнить и умножение и вывод
    (a *= b).show();
    return 0;
} 

Обновление:

Fraction Fraction::operator +(ll_int v){...} Это определение оператора, суммирующая дробь с числом(обьектом v типа long long) . Обьект v не содержится в вашем классе, поэтому x = x * y.v + x.v * y; это ошибка. Если хотите, чтобы операнд был не дробью, а так, как вы пытаетесь, то нужно сделать то же самое, как я вам показал, с разницей, что знаменатель равен 1:

Fraction Fraction::operator +(ll_int v)
{   
    Fraction  f;   // значения по умолчанию f.x == 0 и f.y == 1     
    f.x = x  + v * y;  
    f.y = y;          
    //так как нет дроби (`v` - это целое число)
    return f;
} 
READ ALSO
Как запустить gradle task в отдельном .gradle файле

Как запустить gradle task в отдельном .gradle файле

Как запустить gradle task в отдельномgradle файле до assembleDebug

129
Нуждается ли Jackson object mapper в пометке классов как Serializable?

Нуждается ли Jackson object mapper в пометке классов как Serializable?

Есть сущности, которые сериализуются в/из JSON с помощью Jackson object mapper

170
Прерывание потока ввода

Прерывание потока ввода

Допустим есть у меня отдельный поток который в цикле while ожидает ответ от сервера, например:

169
Переменная и ее объем

Переменная и ее объем

Занимает ли переменная место в куче при объявлении? Иными словами, если я захочу объявить переменную, повлияет ли это на объем используемой...

130